当活动被破坏时,活动背叛的不当行为

Sme*_*eet 25 android broadcastreceiver android-lifecycle android-activity back-stack

我有两个活动; 假设A和B activity A是有广播接收器注册侦听将完成活动A.我注册的广播接收器的特定事件 onCreate(),并摧毁它onDestroy()activity A.

为简单起见,有一个buttonactivity B名为"破坏活性的A".当用户点击时button,activity A应该销毁.

通常所有这些都运行顺利,没有任何问题,但问题出现在以下场景中:

1)假设我在activity B,我按Home键将应用程序移动到后台然后如果我使用其他资源繁重的应用程序,Android系统将杀死我的应用程序以释放内存.然后,如果我最近的任务打开我的应用程序时,activity B将被收回,这是onCreate(),onResume()等方法将被调用.现在我按button摧毁activity A,但活动A已经被破坏,所以activity AonCreate(),onResume()等方法将不会被调用之前,除非我去activity Aback button.因此broadcast receiver没有注册来监听事件.

2)当用户在设备的设置中从Developer选项中选择"Do not keep activities"时,会出现同样的问题.

我一直在寻找解决这个问题很长一段时间,但我无法找到合适的答案.处理这种情况的最佳方法是什么?这是Android的错误吗?这个问题应该有一些解决方案.

请帮我.

dha*_*ram 6

如果您Activity A已被Android操作系统本身销毁,则无法跟踪.

有些人建议Activity A通过在onDestroy方法BUT中列出事件来跟踪它, 如果你Activity被系统操作系统杀死然后在这里注意它不会调用那些方法.


You*_*sef 3

在保持当前广播逻辑的同时,无法修复此问题。

在我看来,从后台终止活动并不是正确的方法。您应该强烈考虑更改导航逻辑。

但是,如果您的项目很大,时间是个问题,并且重构是不可能的,那么 AJ 的方法是有效的,但是您提到您有很多活动需要终止,那么他的解决方案实施起来就会变得非常棘手。

我的建议如下。这可能不是最好的主意,但我想不出另一个主意。所以也许这会有所帮助。

您应该具备以下条件:

  • 适用于您所有活动的基础活动。
  • ArrayList<String> activitiesToKill应用程序级别的对象。(如果你没有扩展,Application你可以将它作为静态变量

首先,我们必须确保activitiesToKill当操作系统杀死内存不足的应用程序时,数据不会丢失。在中BaseActivity我们保存列表onSaveInstanceState并在中恢复它onRestoreInstanceState

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("activitiesToKill", activitiesToKill);
}

private void onRestoreInstanceState(Bundle state) {
    if (state != null) {
        activitiesToKill = (ArrayList<String>) state.getSerializable("activitiesToKill");
    super.onRestoreInstanceState(state); 
}
Run Code Online (Sandbox Code Playgroud)

}

这里的想法是通过使用活动的名称来保存应在列表中终止的活动。

逻辑如下:

假设您有活动 A、B、C、D 和 E

在活动 E 中,您按下按钮并想要杀死 B 和 D

当您按下 E 中的按钮时,您将 B 和 D 的名称添加到对象中activitiesToKill

activitiesToKill.add(B.class.getSimpleName()
activitiesToKill.add(D.class.getSimpleName()
Run Code Online (Sandbox Code Playgroud)

onCreateBaseActivity 的方法中,我们必须检查是否

if(savedInstanceState != null)
{
    //The activity is being restored. We check if the it is in the lest to Kill and we finish it                
    if(activitiesToKill.contains(this.getClass().getSimpleName()))
    {
        activitiesToKill.remove(this.getClass().getSimpleName())
        finish();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果活动通过广播被终止,请确保删除该活动的名称。

所以基本上这就是每个场景中都会发生的情况。

如果应用程序正常运行,并且您单击按钮,则会发送广播,并且 B 和 D 将被杀死。确保从中删除 B 和 DactivitiesToKill

如果应用程序被杀死并恢复,你按下按钮,广播将没有效果,但你已经将B和D添加到对象中activitiesToKill。因此,当您单击“后退”时,该活动已创建并且savedInstanceState不为空,该活动已完成。

这种方法认为活动 E 知道它必须杀死哪些活动。

如果您不知道要从 E 中终止哪些活动,则必须稍微修改此逻辑:

不使用 ArrayList,而是使用HashMap<String, bool>

当 Activity B 创建时,它会将自己注册到 hashmap 中:

activitiesToKill.put(this.class.getSimpleName(), false)
Run Code Online (Sandbox Code Playgroud)

然后从活动 E 中,您所要做的就是将所有条目设置为true

然后在创建基本活动时,您必须检查该活动是否在 eventsToKill 中注册(哈希图包含密钥),并且布尔值是true您杀死它(不要忘记将其返回为 false,或删除密钥)

这确保每个活动将自身注册到 HashMap,并且活动 E 不知道要杀死的所有活动。并且不要忘记删除它们,以防广播杀死它们。

这种方法还确保从意图正常打开时活动不会被终止,因为在这种情况下 onSaveInstanceState 在 onCreate 中将为 null,因此不会发生任何事情。

如果您有需要通过不同条件(不仅仅是单击按钮)终止的活动组,则可以完成更高级的检查,以便您可以使用 HashMap 的 HashMap 将它们划分为类别。

另请注意,如果您有多个名称相同但捆绑包不同的活动,则可以使用 getName 而不是 getSimpleName。

我希望我的解释足够清楚,因为我是从我的脑海中写出来的,如果有任何不清楚的地方,请告诉我。

祝你好运