2

我目前设法允许用户在两​​个不同的活动组之间切换(让我们说 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

我注意到它只发生在同一个班级(B并且B2是同一个班级),如果我使用Band C,它不会出现这样的问题,我想知道背后的原因是什么。

X ->(start) Y也是重现它的关键。

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

4

1 回答 1

1

我误解了FLAG_ACTIVITY_REORDER_TO_FRONT国旗。我认为活动 YFLAG_ACTIVITY_REORDER_TO_FRONT 活动 C 将保留父项,因此 C 后压将转到 B。不,事实并非如此。FLAG_ACTIVITY_REORDER_TO_FRONT实际上使 C 转移到新的父 Y(即调用者),但由于父 Y 在 C 之上,所以 C 后压将无法转到 Y 并最小化/隐藏到背景。

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

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

  • 启动器活动 A 和 X 都必须singleInstance在清单中定义。
  • 主页活动 B 和 Y 都必须singleTop 在清单中定义。
  • 其他活动 C 和 Z ...等必须 singleTask在清单中定义。

Activity A 必须Intent.FLAG_ACTIVITY_MULTIPLE_TASK在启动主页 B 时设置标志。X 也应Intent.FLAG_ACTIVITY_MULTIPLE_TASK在启动主页 Y 时设置标志。

如果选项卡任务之前已经开始,则循环以重新排序所有相同任务活动(存储在全局堆栈列表中)的有效标志是(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清单并执行此操作(更多信息,请参阅此错误报告):

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;

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模式,请参阅此线程。并且不要做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();
}

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

就是这样,这个答案可能缺少代码细节,但如果你遇到像我一样的“回压时隐藏到后台”问题,它应该会有所帮助,你可以了解如果你在一步中设置了错误的标志或launchMode在清单中的一项活动中定义错误。

于 2018-12-25T03:33:04.663 回答