Android重启MainActivity因View已存在父布局崩溃问题求助
解决View已有父容器导致的Activity启动崩溃问题
这个问题我之前做Android小游戏的时候也碰到过,核心原因很明确:你的myView1和myView2是MainActivity的成员变量,当你从GameOverscreen重启MainActivity时,新的Activity实例会重复执行addView操作,但此时这些View还绑定着上一次MainActivity中的父布局——Android不允许一个View同时属于两个父容器,所以就抛出了IllegalStateException异常。
下面给你几个可行的解决方案,按推荐程度排序:
方案1:每次启动MainActivity都创建全新的View实例
这是最稳妥的解决方式,直接避免复用旧View带来的冲突。把myView1和myView2从成员变量改成onCreate方法内的局部变量,每次启动Activity都新建实例:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_main_activity_layout); // 替换成你的布局ID // 新建MyView1实例并添加到布局 MyView1 myView1 = new MyView1(this); RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(480, 900); myView1.setLayoutParams(params1); RelativeLayout layout1 = (RelativeLayout) findViewById(R.id.relative1); myView1.setBackgroundColor(Color.YELLOW); layout1.addView(myView1); // 新建MyView2实例并添加到布局 MyView2 myView2 = new MyView2(this); RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(300,300); myView2.setLayoutParams(params2); RelativeLayout layout2 = (RelativeLayout) findViewById(R.id.relative2); myView2.setBackgroundColor(Color.GREEN); layout2.addView(myView2); }
这样每次启动MainActivity都是全新的View对象,不存在父容器绑定冲突的问题。
方案2:复用View前先移除旧的父容器绑定
如果因为业务需求(比如要保留View的状态)必须复用旧的View实例,那在执行addView之前,先检查View是否已有父容器,若有则先移除:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_main_activity_layout); // 处理MyView1 if (myView1 != null) { // 检查是否有父容器,有则移除 ViewGroup parent = (ViewGroup) myView1.getParent(); if (parent != null) { parent.removeView(myView1); } // 重新添加到新的布局 RelativeLayout layout1 = (RelativeLayout) findViewById(R.id.relative1); layout1.addView(myView1); } else { // 第一次创建时初始化 myView1 = new MyView1(this); RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(480, 900); myView1.setLayoutParams(params1); myView1.setBackgroundColor(Color.YELLOW); RelativeLayout layout1 = (RelativeLayout) findViewById(R.id.relative1); layout1.addView(myView1); } // 同理处理MyView2 if (myView2 != null) { ViewGroup parent = (ViewGroup) myView2.getParent(); if (parent != null) { parent.removeView(myView2); } RelativeLayout layout2 = (RelativeLayout) findViewById(R.id.relative2); layout2.addView(myView2); } else { myView2 = new MyView2(this); RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(300,300); myView2.setLayoutParams(params2); myView2.setBackgroundColor(Color.GREEN); RelativeLayout layout2 = (RelativeLayout) findViewById(R.id.relative2); layout2.addView(myView2); } }
不过这种方式要注意:如果上一个MainActivity已经被系统回收,它的父布局可能已经不存在,直接操作可能引发其他隐性问题,所以优先推荐方案1。
额外优化:启动MainActivity时清除旧实例
从GameOverscreen跳转回MainActivity时,最好给Intent添加标记,确保启动的是全新的Activity实例,避免旧实例的状态残留:
// 在GameOverscreen中启动MainActivity的代码 Intent restartIntent = new Intent(this, MainActivity.class); // 清除返回栈中MainActivity之上的所有Activity,并启动新实例 restartIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(restartIntent); finish(); // 关闭当前GameOverscreen,避免返回栈混乱
内容的提问来源于stack exchange,提问作者Marten
相关产品推荐
相关产品推荐

