安卓开发调用Fragment方法触发NullPointerException空指针崩溃求助
问题根因
- 核心原因是
MainActivity中底部导航的探索页逻辑重复实例化了ExploreFragment:你先创建了一个ExploreFragment实例提交到容器中,随后又新建了另一个完全独立的ExploreFragment实例调用ExtractMemes方法。第二个实例没有被添加到Fragment栈,不会执行onCreateView生命周期方法,你声明的成员变量ArrayList<exploreclass> list只在onCreateView中初始化,所以调用list.add()时就会触发空指针异常。 - 同时存在多个潜在的后续崩溃隐患:
ExtractMemes方法中声明了局部变量manager和adapter,没有给类的成员变量赋值,后续滚动加载调用fetchMoreData时,成员变量adapter和manager都是空值,会触发新的空指针- 异步网络请求返回时,可能存在Fragment已经被销毁、上下文不存在的情况,没有做生命周期判断
修复方案
第一步:修改MainActivity中探索页的逻辑
把原来的代码:
case R.id.explore: transaction.replace(R.id.framelayout, new ExploreFragment()); ExploreFragment exploreFragment = new ExploreFragment(); exploreFragment.ExtractMemes(getApplicationContext(), "https://meme-api.herokuapp.com/gimme/30"); break;
改为:
case R.id.explore: ExploreFragment exploreFragment = new ExploreFragment(); transaction.replace(R.id.framelayout, exploreFragment); break;
主动调用网络请求的逻辑放到Fragment自己的生命周期中触发更符合安卓开发规范,避免生命周期不同步的问题。
第二步:调整ExploreFragment的初始化逻辑
将网络请求触发放到Fragment的onViewCreated方法中,同时修正成员变量赋值的问题:
- 在
onCreateView的return view之前添加如下代码,完成基础组件初始化:
manager = new LinearLayoutManager(getContext()); rcv1_explore.setLayoutManager(manager); adapter = new explore_adapter(list, getContext()); rcv1_explore.setAdapter(adapter); // 在这里触发网络请求,不用Activity主动调用 ExtractMemes(requireContext(), "https://meme-api.herokuapp.com/gimme/30");
- 修改
ExtractMemes方法,去掉局部的manager和adapter声明,只更新数据后通知适配器刷新,同时增加生命周期判断:
public void ExtractMemes(Context context, String url) { RequestQueue queue = Volley.newRequestQueue(context); JsonObjectRequest response = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { // 先判断Fragment是否还附着在Activity上,避免生命周期问题 if (!isAdded()) return; try { JSONArray memes_array = response.getJSONArray("memes"); for(int i=0; i<memes_array.length(); i++) { JSONObject memes_object = memes_array.getJSONObject(i); exploreclass class_object = new exploreclass(); class_object.setUps(memes_object.getInt("ups")); class_object.setUrl(memes_object.getString("url")); class_object.setPostLink(memes_object.getString("postLink")); list.add(class_object); } adapter.notifyDataSetChanged(); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { if (!isAdded()) return; Toast.makeText(getContext(), error.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); } }); queue.add(response); }
第三步:优化fetchMoreData方法
在fetchMoreData的网络回调开头同样加上if (!isAdded()) return;的判断,避免Fragment销毁后回调触发空指针。
内容的提问来源于stack exchange,提问作者Jeet Saluja
相关产品推荐
相关产品推荐

