重新排序前后后如何修复应用程序进入后台

时间:2018-12-13 18:29:51

标签: android-intent android-activity android-background android-task

我目前设法允许用户在两​​个不同的活动组(让我们说4个活动类别A / B组和X / Y组)之间切换,并通过FLAG_ACTIVITY_REORDER_TO_FRONT标志进行切换,但是我注意到有一些奇怪的行为:

A ->(start activity)  X
X ->(reorder to front) A 
X , A ->(start) B ->(start) B2
A , B , B2 ->(reorder to front) X ->(start) Y
X , Y ->(reorder to front) A , B , B2 
X , Y , A , B <-(press back, app hide to background, B2 destroyed)  B2 
X , Y , A , B (click to foreground, B is here just fine)

B2返回后,如何防止应用隐藏到后台?

我注意到它仅在同一类中发生(BB2是同一类),如果我使用BC,就不会出现此类问题,我想知道背后的原因是什么。

X ->(start) Y也是复制它的关键。

我尝试使用应用程序级别的自定义实例列表来检测B2的{​​{1}}的{​​{1}}和onPause()isFinishing(),但是它将始终即使使用startActivty()也会调用B的{​​{1}},这使我认为这不是正确的解决方案。正确的解决方案应该弄清楚如何防止应用隐藏到后台。

1 个答案:

答案 0 :(得分:0)

我误解了FLAG_ACTIVITY_REORDER_TO_FRONT标志。我认为活动Y FLAG_ACTIVITY_REORDER_TO_FRONT的活动C将保留父项,因此C后退将转到B。不,不是这样。 FLAG_ACTIVITY_REORDER_TO_FRONT实际上是将C转移到新的父Y(即调用方),但是由于父Y位于C的顶部,因此C backpress将无法转到Y并最小化/隐藏到背景。

我也误解了我的代码创建2个堆栈,但实际上它只是单个堆栈。我必须使用FLAG_ACTIVITY_MULTIPLE_TASK使其多堆。

我还需要在清单中定义正确的launchMode

  • 启动器活动A和X必须在以下位置定义为singleInstance 表现。
  • 首页活动B和Y都必须定义为singleTop 在清单中。
  • 其他活动C和Z ... etc必须定义为 清单中的singleTask

活动A在开始首页B时必须设置标志Intent.FLAG_ACTIVITY_MULTIPLE_TASK。 在开始首页Y时,X还应设置标志Intent.FLAG_ACTIVITY_MULTIPLE_TASK

如果选项卡任务之前已经开始,则循环以对所有相同的任务活动(存储在全局堆栈列表中)重新排序的有效标志是(moveTaskToBack(true);单行也可以,无法回到前台):

intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
                            |Intent.FLAG_ACTIVITY_NEW_TASK
                            |Intent.FLAG_ACTIVITY_NO_ANIMATION); 

p / s:以上内容在Android 5和6中不起作用,它们只会将单个顶级活动重新排序到前面,因此我需要在清单中添加android.permission.REORDER_TASKS并执行此操作(更多信息,{{3 }}):

ActivityManager tasksManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (final Activity a : YStackClasses) {
    if (IsBeforeAndroidNougat && (tasksManager != null)) {
        tasksManager.moveTaskToFront(a.getTaskId(), ActivityManager.MOVE_TASK_NO_USER_ACTION); 
    } else { 
        //Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
    }
}

如果选项卡任务从未启动,则应在不设置任何特殊标志的情况下启动启动器活动。

为防止单击启动器由于singleInstance而刷新,我还必须检查A和B,并将其放在setContentViewfinish() / return;之前。 / p>

if (getIntent() != null && getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)
    && getIntent().getAction() != null
    && getIntent().getAction().equals(Intent.ACTION_MAIN)) {
    //figure out latest activity and it's home activity, and reorder to front, and its entire task stack will focus on top.
}

Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK将不再自动清除所有活动以刷新应用程序,解决方案为ActivityCompat.finishAffinity(desiredTask's Top Act);,这将删除顶部活动下方的所有活动,而不会影响其他任务堆栈。

如果该类正在重用,例如C1,C2,那么我必须使用startActivityForResult(intent, dummyResponse);来强制它在同一类的顶部创建新的活动。但是当A开始活动B时,startActivityForResult仅需要一项任务,而忽略singleInstance launchMode see this bug report,则不要这样做。并且不要在ForResult内执行onNewIntent(),这可能会导致页面在堆栈中生成两次(第二个页面不会立即生成,而是仅在返回时生成)。但是我可以在ForResult的调用者中执行onNewIntent()来生效。

我还需要执行此操作,以使家庭活动中的backpress正常工作,以隐藏应用程序并能够返回正确的任务页面。我不使用TASK_ON_HOME(当开始首页B类时)标志,因为它只是单个任务方向(即,从前台到固定活动,而不是取决于先前的最高任务活动):

@Override //B class
public void onBackPressed() {
    moveTaskToBack(true); //B task stack
    if (YStackClasses.size() > 0) { //Y task stack
        try {
            YStackClasses.get(0).moveTaskToBack(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    super.onBackPressed();
}

请注意,即使由于崩溃而自动重新启动,应用程序堆栈也可能会缓存,因此有时您需要重新启动两次以使其回到初始堆栈状态进行测试,否则您将得出错误的结论。

就是这样,此答案可能缺少代码详细信息,但是如果您遇到像我这样的“ backpress时隐藏背景” 问题,它应该会有所帮助,您可以了解很难达到预期的效果如果您在一个步骤中设置了错误的标志,或者在清单中的活动之一中定义了错误的launchMode,则会发生这种情况。