使用FLAG_ACTIVITY_REORDER_TO_FRONT在持续运行的UI活动之间切换会导致“无窗口焦点”错误。

9
我的目标是保持两个UI活动的活跃,并且可以在它们之间自由切换,而不必杀死/重新启动它们。但是,使用FLAG_ACTIVITY_REORDER_TO_FRONT会导致一个严重的副作用:当我恢复先前的活动(当前在后台运行)时,会失去窗口焦点。
我通过创建一个简单的应用程序来证明这个问题,只需要花费5分钟即可创建两个“Hello World”活动。
1. 应用程序从Activity A开始,它只显示一个名为“Launch B”的按钮(没有其他内容)。 2. 按下此按钮--这将执行startActivity(FLAG_ACTIVITY_REORDER_TO_FRONT, ActivityB.class)。 3. Activity B变为活动状态,它只显示一个名为“Launch A”的按钮。 4. 按下此按钮--这将执行startActivity(FLAG_ACTIVITY_REORDER_TO_FRONT, ActivityA.class)。 5. 如预期地调用了Activity A的onResume(),一切看起来都很好(我可以再次看到Activity A的内容)。 6. 按设备的返回键,这组错误将100%发生:
E/ActivityManager( 513): Reason: Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.) I/WindowState( 513): WIN DEATH: Window{5294687c u0 com.android.launcher/com.android.launcher2.Launcher} W/ViewRootImpl( 8066): Dropping event due to no window focus: KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0xc8, repeatCount=1, eventTime=14965546, downTime=14965045, deviceId=-1, source=0x101 }
(窗口死亡的实际结果从用户的角度来看基本上是一个“崩溃” - Android将用户从应用程序中扔回到主屏幕,尽管从技术上讲应用程序仍在后台运行。)
我调试了这个问题,并发现Activity A可见但没有焦点的原因是因为Activity A的onWindowFocusChanged()没有像通常一样被调用(尽管onResume()被调用)。这与Activity B仍然在后台活动有关(尽管B已失去焦点--对于B,onWindowFocusChanged(false)已被调用,以及onStop())。我知道这一点,因为在上述第4步之后,如果我立即在Activity B上调用finish(),Activity A的onWindowFocusChanged(true)将被调用,一切都正常。事实上,Activity B仍然处于活动状态但没有焦点,某种程度上会干扰Activity A恢复焦点,就像它应该做的那样。这是Android的错误还是我错过了什么?
请注意,如果Activity A中有多个视图,并且在完成上述第6步后我触摸其中一个视图,则会出现相同的“由于没有窗口焦点而丢弃事件”错误,尽管出现此错误的概率不是100%,原因未知。

这是Lollipop中引入的一个错误,请参见:https://code.google.com/p/android/issues/detail?id=91534 - xizzhu
1
好的,实际上这个 bug 是在 4.4.2 版本中引入的:https://code.google.com/p/android/issues/detail?id=63570 - xizzhu
1
问题陈述清晰,关于原因有很好的想法!顺便说一下,这也在http://stackoverflow.com/questions/29804474和https://dev59.com/A43da4cB1Zd3GeqPuAU2上被跟踪。 - Jo Jo
很遗憾,我还没有找到解决这个问题的方法。在我的项目中,“Activity A”始终处于活动状态,因此当我从“Activity B”切换到A时,我总是立即杀死B。这是我唯一的解决方法。我本来更喜欢保持B开启,而不是之后再重新启动它,但我看不到其他防止崩溃的方法。 - Steve B
1个回答

1

这个https://code.google.com/p/android/issues/detail?id=63570#c15中提供的解决方法,对于我解决Activity无法获取窗口焦点的问题非常有效:

protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    if ((intent.getFlags() | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) > 0) {
        if (android.os.Build.VERSION.SDK_INT >= 19 && !isTaskRoot()) {
            ActivityManager tasksManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
            tasksManager.moveTaskToFront(getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION);
        }
    }
}

这也需要在AndroidManifest.xml中获取权限。
<uses-permission android:name="android.permission.REORDER_TASKS" />

我在Espresso测试中遇到了这个问题,出现了以下错误:

java.lang.RuntimeException:等待视图层次结构的根具有窗口焦点并且未请求布局超过10秒。如果您指定了非默认根匹配器,则可能选择从不获取焦点的根。否则,出现了严重问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接