Android Fragment中AlertDialog二次触发崩溃:IllegalStateException问题
这个问题我之前碰过好多次,本质就是Android的View绑定规则在起作用——一个View实例不能同时属于两个父容器。你第一次弹出Dialog时,已经把ListView添加到了Dialog的布局容器里,当Dialog关闭时,这个ListView和它的父容器(Dialog的内部布局)的关联并没有被切断。第二次再想把同一个ListView实例塞进新的Dialog里,系统就会抛出那个IllegalStateException,告诉你必须先把它从原来的父容器里移除。
给你几个靠谱的解决方案,按需选择:
方案1:每次创建Dialog都用全新的ListView实例
这是最省心的做法,不要把ListView做成全局变量或者复用同一个实例,而是每次触发Dialog时,都重新加载布局或者实例化ListView:
// 比如在触发Dialog的点击事件里写: public void showListDialog(Context context) { // 每次都inflate新的布局,拿到新的ListView View dialogContent = LayoutInflater.from(context).inflate(R.layout.dialog_list_layout, null); ListView listView = dialogContent.findViewById(R.id.dialog_list); // 给ListView设置Adapter(如果需要,Adapter也可以按需重新创建) ArrayAdapter<String> adapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, yourDataList); listView.setAdapter(adapter); // 创建并显示Dialog new AlertDialog.Builder(context) .setTitle("选择选项") .setView(dialogContent) .setPositiveButton("确定", null) .create() .show(); }
这样每次弹出的Dialog都用的是全新的ListView,自然不会有“重复父容器”的问题。
方案2:复用ListView前先移除它的父容器
如果你因为某些原因必须复用同一个ListView实例,那要在每次Dialog关闭时,手动把ListView从它的父容器里剥离:
// 假设你的ListView是全局变量或者能拿到引用 ListView reusableListView; public void showReusableListDialog(Context context) { AlertDialog dialog = new AlertDialog.Builder(context) .setTitle("复用ListView") .setView(reusableListView) .setPositiveButton("确定", null) .create(); // 给Dialog设置关闭监听,移除ListView的父容器 dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { ViewParent parent = reusableListView.getParent(); if (parent != null && parent instanceof ViewGroup) { ((ViewGroup) parent).removeView(reusableListView); } } }); dialog.show(); }
这样下次再把这个ListView添加到新Dialog时,它已经没有父容器了,就不会报错。
方案3:用Dialog自带的setItems方法(适合简单文本列表)
如果你的列表只是简单的文本选项,完全不用自己写ListView,直接用AlertDialog.Builder的setItems方法,Android会帮你处理所有View的复用和生命周期问题:
public void showSimpleListDialog(Context context) { String[] options = {"选项1", "选项2", "选项3"}; new AlertDialog.Builder(context) .setTitle("简单列表") .setItems(options, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 处理对应选项的点击事件 Toast.makeText(context, "你选了" + options[which], Toast.LENGTH_SHORT).show(); } }) .setNegativeButton("取消", null) .create() .show(); }
这种方法最简洁,还能避免手动管理ListView带来的各种问题。
总结一下:核心就是记住一个View只能有一个父容器,要么每次用新View,要么复用前先断开关联,就能解决这个崩溃问题啦!
内容的提问来源于stack exchange,提问作者Siva chidambaram

