Fragment未关联上下文异常:Toolbar按钮调用Fragment方法报错
问题原因分析
从报错信息和你的代码来看,核心问题出在Activity的onOptionsItemSelected方法里:
ListFragment listFragment = new ListFragment(); listFragment.sortByPopularity();
你在这里新建了一个ListFragment实例,但这个实例从来没有通过FragmentTransaction添加到Activity的FragmentManager中,完全没有依附于任何上下文(Context)。当你调用sortByPopularity方法时,里面的getString(R.string.api_key)需要依赖Fragment的上下文,而此时Fragment还没依附到Activity,自然就抛出了IllegalStateException: Fragment not attached to a context的异常。
更关键的是,这个新建的Fragment实例和你之前显示在界面上的ListFragment完全是两个不同的对象,就算不报错,调用它的方法也不会更新界面上的列表。
解决方案
你需要获取当前已经添加到Activity中的那个ListFragment实例,而不是新建。具体步骤如下:
修改Activity中的调用代码:
根据你的Fragment容器ID(也就是R.id.main_frame_list),通过findFragmentById获取已存在的实例:@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.menu_sort: // 获取当前已显示的ListFragment实例 ListFragment listFragment = (ListFragment) getSupportFragmentManager() .findFragmentById(R.id.main_frame_list); if (listFragment != null && listFragment.isAdded()) { // 确保Fragment已依附到Activity再调用方法 listFragment.sortByPopularity(); } break; } return super.onOptionsItemSelected(item); }如果你的Fragment是通过标签(tag)添加的,也可以用
findFragmentByTag("你的Fragment标签")来获取。优化Fragment的sortByPopularity方法:
为了避免后续可能出现的上下文问题,同时修复列表重复添加数据的问题,建议做如下修改:public void sortByPopularity() { // 先判断Fragment是否已依附上下文 if (!isAdded()) { return; } RetrofitClient.getApiService().getPopularList(getString(R.string.api_key)).enqueue(new Callback<BasePojo>() { @Override public void onResponse(Call<BasePojo> call, Response<BasePojo> response) { BasePojo basePojo = response.body(); if (basePojo != null && basePojo.getResults() != null) { // 清空原有列表再添加新数据,避免重复展示 list.clear(); list.addAll(basePojo.getResults()); listAdapter.notifyDataSetChanged(); } } @Override public void onFailure(Call<BasePojo> call, Throwable t) { Log.d("tag", "Response failed" + t.toString()); } }); }
额外注意事项
- 永远不要直接新建Fragment实例来调用它的业务方法,必须操作当前界面上已存在的实例。
- 在Fragment中调用需要上下文的方法(比如
getString、getActivity())时,最好先通过isAdded()或者getActivity() != null来判断是否已依附,避免空指针或上下文异常。
内容的提问来源于stack exchange,提问作者Bo Z

