Android Studio自定义ListView加载JSON致应用崩溃求助
看起来你遇到的崩溃大概率是由空指针异常导致的,我帮你梳理了代码里的几个关键问题,逐个修复就能解决:
1. 自定义适配器(CustomAdapter)中的空指针问题
你的CustomAdapter里声明了ArrayListCountries,但从未在构造函数中初始化赋值,导致调用getView()时ArrayListCountries.get(Position)直接抛出空指针,这是最可能的崩溃原因。
修复后的CustomAdapter代码:
public class CustomAdapter extends ArrayAdapter<Country> { public ArrayList<Country> ArrayListCountries; public CustomAdapter(@NonNull Context context, int resource, ArrayList<Country> Countries) { super(context, R.layout.activity_main_list, Countries); // 初始化成员变量,把传入的数据源赋值给ArrayListCountries this.ArrayListCountries = Countries; } @Override public View getView(int Position, View view, ViewGroup viewgroup) { // 复用convertView优化性能,避免每次都inflate新布局 if (view == null) { LayoutInflater Inflater = LayoutInflater.from(getContext()); view = Inflater.inflate(R.layout.activity_main_list, viewgroup, false); } // 现在可以安全获取数据了 Country country = ArrayListCountries.get(Position); TextView CountryText = view.findViewById(R.id.CountryNameText); ImageView CountryImage = view.findViewById(R.id.CountryImage); CountryText.setText(country.name); // 补充:如果需要加载网络图片,建议用Glide/Picasso,这里先留个占位 // Glide.with(getContext()).load(country.image).into(CountryImage); return view; } }
2. Main类中Firebase初始化的空指针
你的FirebaseAuthentication变量没有初始化就调用getInstance(),会导致空指针:
// 原代码错误: FirebaseInstance = FirebaseAuthentication.getInstance(); // 修复:直接初始化FirebaseInstance FirebaseInstance = FirebaseAuth.getInstance();
修改Main类的onCreate部分:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getSupportActionBar().setTitle("Dashboard"); UserEmailText = findViewById(R.id.UserEmail); // 修复Firebase初始化 FirebaseInstance = FirebaseAuth.getInstance(); LoggedInUser = FirebaseInstance.getCurrentUser(); UserEmailText.setText(LoggedInUser.getEmail()); CountryList = new ArrayList<>(); CountryListView = findViewById(R.id.CountryList); new GetCountries().execute(); }
3. 退出登录时ProgressDialog的空指针风险
在onOptionsItemSelected的退出分支里,你直接调用ProgressDialog.setMessage(),但ProgressDialog是在GetCountries的onPreExecute()中才初始化的。如果用户还没加载过列表就点退出,ProgressDialog是null,会崩溃。
修复方案:提前初始化ProgressDialog,或者在使用前判空:
// 在Main类的成员变量初始化时就创建ProgressDialog(推荐) private ProgressDialog ProgressDialog; @Override protected void onCreate(Bundle savedInstanceState) { // ...其他代码 ProgressDialog = new ProgressDialog(Main.this); ProgressDialog.setCancelable(false); } // 退出登录分支修改: else if(item.getItemId() == R.id.MenuItem2){ FirebaseAuth.getInstance().signOut(); ProgressDialog.setMessage("Signing out..."); ProgressDialog.show(); // 注意:先显示弹窗再跳转,避免弹窗还没显示就finish了 OpenBeginningActivity(); }
4. JSON解析中的异常处理优化
在doInBackground的catch块里,你直接修改ProgressDialog的消息,但doInBackground是子线程,不能直接操作UI,会导致崩溃。应该把错误消息传到onPostExecute处理:
修改GetCountries类:
private class GetCountries extends AsyncTask<Void, Void, String> { // 把返回类型改成String,用来传递错误信息 @Override protected void onPreExecute() { super.onPreExecute(); ProgressDialog.setMessage("Please wait..."); ProgressDialog.show(); } @Override protected String doInBackground(Void... voids) { HttpHandler Handler = new HttpHandler(); String JSONString = Handler.makeServiceCall(JSONUrl); Log.e(TAG, "Response:" + JSONString); if(JSONString != null){ try { JSONObject CountriesJSONObject = new JSONObject(JSONString); JSONArray Countries = CountriesJSONObject.getJSONArray("countries"); for (int i = 0; i < Countries.length(); i++) { JSONObject Country = Countries.getJSONObject(i).getJSONObject("country"); String CountryID = Country.getString("id"); String CountryName = Country.getString("name"); String CountryImage = Country.getString("image"); CountryList.add(new Country(CountryID, CountryName, CountryImage)); } return null; // 没有错误返回null } catch (final JSONException e){ Log.e(TAG,e.getMessage()); return "Error loading Data!"; // 返回错误信息 } } else { return "Failed to get data from server!"; } } @Override protected void onPostExecute(String errorMsg) { ProgressDialog.dismiss(); if(errorMsg != null){ // 用Toast显示错误信息 Toast.makeText(Main.this, errorMsg, Toast.LENGTH_SHORT).show(); return; } ListAdapter CustomAdapter = new CustomAdapter(Main.this,0,CountryList); CountryListView.setAdapter(CustomAdapter); } }
把这些修复点全部应用后,你的ListView应该就能正常加载数据,不会崩溃了。另外建议你打开Android Studio的Logcat,查看崩溃时的具体异常信息,这是调试这类问题最快的方式。
内容的提问来源于stack exchange,提问作者VallyMan

