如何在Fragment中向自定义ListView Adapter传递Activity上下文
问题根源分析
我一眼就看到问题所在了——你在Fragment的成员变量初始化阶段就直接调用this.getActivity()来获取上下文,这时候Fragment还没依附到Activity上(Fragment的onAttach生命周期方法都还没执行),所以getActivity()会返回null!后续用这个空上下文去创建Adapter、ProgressDialog或者Toast,自然会出问题。
解决方案步骤
1. 移除无效的提前初始化代码
先删掉Fragment里这两行错误的上下文初始化:
Context siblingContext = this.getActivity(); Activity context = this.getActivity();
2. 在合适时机获取安全上下文
在Fragment生命周期的onActivityCreated、onCreateView之后,或者在需要使用上下文的方法内部,用requireActivity()(获取Activity实例)或requireContext()(获取Context实例)来获取有效上下文。这两个方法比getActivity()更安全——如果上下文为空会直接抛出异常,方便你快速定位问题,而不是默默返回null导致难以排查的崩溃。
3. 优化Adapter的上下文参数(可选但推荐)
你的Adapter构造函数目前要求传入Activity,其实Adapter只需要Context就足够完成布局加载等操作。把Adapter的构造函数改成接受Context,能让它的复用性更强:
// 修改前的构造函数 // public SiblingsListViewAdapter(Activity context, String[] Uuid, String[] Usize, String[] Ustatus) // 修改后的构造函数 public SiblingsListViewAdapter(Context context, String[] Uuid, String[] Usize, String[] Ustatus) { super(); this.context = context; this.Uuid = Uuid; this.Usize = Usize; this.Ustatus = Ustatus; }
4. 替换Fragment中所有上下文调用
把Fragment里用到上下文的地方,都换成安全的获取方式:
- ProgressDialog初始化:
progressDialog = ProgressDialog.show(requireActivity(), "Loading Data", null, true, true);
- 创建Adapter:
siblingLVAdapter = new SiblingsListViewAdapter(requireActivity(), Uuid, Usize, Ustatus); // 或者用requireContext(),两者都可以,取决于是否需要Activity的特定方法 // siblingLVAdapter = new SiblingsListViewAdapter(requireContext(), Uuid, Usize, Ustatus);
- Toast提示:
Toast.makeText(requireContext(), "Error: " + e.toString(), Toast.LENGTH_LONG).show();
修改后的完整Fragment关键代码
public class SiblingUnitFragment extends Fragment { ProgressDialog progressDialog; ListView siblingLVAdapter; String ReadOnly; String LexaUser; String Password; String SearchValue; String finalResultSiblings; String HttpURLSiblings = "https://[myDataSpot]/getSiblings.php"; HashMap<String, String> hashMapSiblings = new HashMap<>(); HttpParse httpParse = new HttpParse(); String[] Uuid; String[] Usize; String[] Ustatus; String SV; String[] svSeparated; ListView siblingListView; public SiblingUnitFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_siblings, container, false); siblingListView = (ListView) view.findViewById(R.id.SiblingsList); return view; } public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (getArguments() != null) { SV = getArguments().getString("SearchValue"); LexaUser = getArguments().getString("LexaUser"); } if (SV.contains("-")) { svSeparated = SV.split("-"); SearchValue = svSeparated[0]; getSiblings(SearchValue, LexaUser); } else { SearchValue = SV; getSiblings(SearchValue, LexaUser); } } public void getSiblings(String searchInput, String lexaUser) { class SiblingsClass extends AsyncTask<String,Void,String> { @Override protected void onPreExecute() { super.onPreExecute(); progressDialog = ProgressDialog.show(requireActivity(), "Loading Data", null, true, true); } @Override protected void onPostExecute(String httpResponseMsg) { super.onPostExecute(httpResponseMsg); if (httpResponseMsg != null) { try { JSONArray json = new JSONArray(httpResponseMsg); Uuid = new String[json.length()]; Usize = new String[json.length()]; Ustatus = new String[json.length()]; for (int i = 0; i < json.length(); i++) { JSONObject object = json.getJSONObject(i); Uuid[i] = object.getString("id"); Usize[i] = object.getString("size"); Ustatus[i] = object.getString("status"); } siblingLVAdapter = new SiblingsListViewAdapter(requireActivity(), Uuid, Usize, Ustatus); siblingListView.setAdapter(siblingLVAdapter); } catch (JSONException e) { Log.e("JSONException", "Error: " + e.toString()); Toast.makeText(requireContext(), "Error: " + e.toString(), Toast.LENGTH_LONG).show(); } progressDialog.dismiss(); } else { progressDialog.dismiss(); Toast.makeText(requireContext(), "HttpResponseMsg is null.", Toast.LENGTH_LONG).show(); } } @Override protected String doInBackground(String... params) { hashMapSiblings.put("searchinput", params[0]); hashMapSiblings.put("lexauser", params[1]); finalResultSiblings = httpParse.postRequest(hashMapSiblings, HttpURLSiblings); return finalResultSiblings; } } SiblingsClass siblingsClass = new SiblingsClass(); siblingsClass.execute(searchInput, lexaUser); } }
额外最佳实践建议
- 尽量避免在Fragment中持有Activity的强引用,除非确实需要Activity的特定方法。做布局加载、显示Toast等基础操作时,用
requireContext()就足够了。 - ProgressDialog已经被官方标记为过时,推荐使用
ProgressBar或者Jetpack组件中的ProgressIndicator替代。 - 如果你需要监听Activity的生命周期变化,可以用
getActivityLifecycleOwner()获取LifecycleOwner,配合LiveData等组件使用。
内容的提问来源于stack exchange,提问作者rdimouro
相关产品推荐
相关产品推荐

