Android Fragment交互触发TextView空指针异常求解
问题根因
- 你在MainActivity中试图通过
findViewById(R.id.tvDescription)获取的TextView控件,并不属于activity_main.xml的布局,这个控件实际定义在DetailFragment的布局文件中,属于DetailFrag的私有布局控件,Activity无法直接在自身onCreate阶段找到它,所以tvDescription始终为null,调用setText就触发空指针。 - 额外的时序问题:你在ListFrag的
onActivityCreated中提前调用了activity.onItemSelected(0),此时Activity和Fragment的生命周期还未完全同步,就算控件位置正确也可能出现空指针。 - 还有一处笔误:你把DetailFrag的布局文件名写为
fragment_deal.xml,和代码中加载的R.layout.fragment_detail不匹配,也可能引发加载异常。
修复步骤
步骤1:调整MainActivity逻辑,不要直接操作Fragment内部控件
修改MainActivity代码,改为获取DetailFrag实例,把要更新的内容传递给Fragment自己处理:
public class MainActivity extends AppCompatActivity implements ListFrag.ItemSelected { ArrayList<String> descriptions; DetailFrag detailFrag; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); descriptions = new ArrayList<>(); descriptions.add("Description for item 1"); descriptions.add("Description for item 2"); descriptions.add("Description for item 3"); // 获取已加载的DetailFrag实例 detailFrag = (DetailFrag) getSupportFragmentManager().findFragmentById(R.id.detailFrag); } @Override public void onItemSelected(int index) { // 把选中的内容传给DetailFrag处理 if (detailFrag != null) { detailFrag.updateDescription(descriptions.get(index)); } } }
步骤2:给DetailFrag新增UI更新方法,自己操作内部控件
修改DetailFrag代码,在自身布局中找控件,对外暴露更新方法:
public class DetailFrag extends Fragment { private TextView tvDescription; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // 加载自身布局 View view = inflater.inflate(R.layout.fragment_detail, container, false); // 在Fragment自己的布局中查找控件 tvDescription = view.findViewById(R.id.tvDescription); return view; } // 对外暴露更新内容的方法 public void updateDescription(String content) { if (tvDescription != null) { tvDescription.setText(content); } } }
步骤3:调整ListFrag的调用时序,避免空指针
修改ListFrag的onActivityCreated方法,删除提前触发的选中回调:
@Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ArrayList<String> data = new ArrayList<String>(); data.add("1.This is item 1"); data.add("2.This is item 2"); data.add("3.This is item 3"); setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, data)); // 删除这行提前调用的代码,避免时序问题 // activity.onItemSelected(0); }
如果需要默认选中第一条内容,可以在DetailFrag的onViewCreated中直接设置默认值:
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); tvDescription.setText("Description for item 1"); }
步骤4:修正布局文件名
把你命名为fragment_deal.xml的布局文件改名为fragment_detail.xml,和代码中加载的布局ID保持一致。
内容的提问来源于stack exchange,提问作者andree_sa
相关产品推荐
相关产品推荐

