重新排序前后后如何修复应用程序进入后台 [英] How to fix app go to background after reorder to front and back

查看:96
本文介绍了重新排序前后后如何修复应用程序进入后台的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I currently managed to allow user switch between two distinct acitivties groups (let's said 4 activity classes A/B group and X/Y group) and switch by FLAG_ACTIVITY_REORDER_TO_FRONT flag, but I noticed there are some strange behaviour:

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返回时如何防止应用隐藏到后台?

How to prevent app hide to background when back from B2 ?

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

I noticed it only happen in same class(B and B2 is same class), if I use B and C, it will no such issue, I wanted to know what's the reason behind.

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

我试图使用应用程序级别的自定义实例列表来检测B2onPause()isFinishing()以及startActivty()B,但是即使它总是会调用BonCreate()尽管使用FLAG_ACTIVITY_REORDER_TO_FRONT,这使我认为这不是正确的解决方案.正确的解决方案应该弄清楚如何防止应用程序隐藏到后台.

I tried to use application-level custom instance list to detect B2's onPause() and isFinishing() and startActivty() the B, but it will always calls B's onCreate() even though using FLAG_ACTIVITY_REORDER_TO_FRONT, which make me think this is not the proper solution. The proper solution should figure out how to prevent the app hide to background.

推荐答案

我误解了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并最小化/隐藏到背景.

I misunderstanding the FLAG_ACTIVITY_REORDER_TO_FRONT flag. I thought activity Y FLAG_ACTIVITY_REORDER_TO_FRONT activity C will retain the parent, so C backpress will go to B. No, this is not the case. FLAG_ACTIVITY_REORDER_TO_FRONT actually make the C transfer to the new parent Y (i.e. the caller), but since parent Y is on top of C, so C backpress will not able goto Y and get minimized/hide to background.

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

I also misunderstanding my code create 2 stack, but actually it's only single stack. I must use FLAG_ACTIVITY_MULTIPLE_TASK to make it multple stacks.

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

I also need to define correct launchMode in manifest:

  • 启动器活动A和X必须在以下位置定义为singleInstance 显现.
  • 首页活动B和Y都必须定义为singleTop 在清单中.
  • 其他活动C和Z ... etc必须定义为 清单中的singleTask.
  • Both launcher activity A and X must defined as singleInstance in manifest.
  • Both home page activity B and Y must defined as singleTop in manifest.
  • Other activities C and Z ...etc must defined as singleTask in manifest.

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

Activity A must set flag Intent.FLAG_ACTIVITY_MULTIPLE_TASK when start home page B. X should also set flag Intent.FLAG_ACTIVITY_MULTIPLE_TASK when start home page Y.

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

If the tab task already started before, the valid flags to loop to reorder all the same task activities (store in global stack list) are (moveTaskToBack(true); single line also works but it not able back to foreground):

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并执行此操作(更多信息,

p/s: The above will not work in Android 5 and 6, which will only reorder single top activity to front, so I need to add android.permission.REORDER_TASKS in manifest and do this (More info, see this bug report):

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
    }
}

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

If the tab task never started, should start launcher activity without set any special flag.

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

To prevent click launcher will refresh due to singleInstance, I must also do checking in A and B, put it before setContentView and finish()/return; early.

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);,它将删除顶部活动下方的所有活动,而不会影响其他任务堆栈.

Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK will no longer auto clear all activities to refresh the app, the solution is ActivityCompat.finishAffinity(desiredTask's Top Act);, which will remove all activites below of top activitiy without affect the other task stack.

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

If the class is reuse, such as C1, C2, then I must use startActivityForResult(intent, dummyResponse); to force it create new acitivty on top of same class. But don't do it when A start activity B since startActivityForResult requires single task and ignore the singleInstance launchMode, see this thread. And don't do ForResult inside onNewIntent() which might causes page generated twice in stack (The second page not generated immediately, instead only generated when back). But I can do ForResult in the caller of onNewIntent() to take effect.

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

I also need to do this to make backpress work as expected in home activity to hide app and able back to the correct task page. I don't use TASK_ON_HOME(when start home page B class) flag because it's only single task direction (i.e. foreground to fixed activity instead of depends on previous top task activity):

@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();
}

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

And be careful the app stack might cache even though relaunch automatically due to crash, so sometime you need relaunch twice to make it back to initial stack state to test, or else you will get the wrong conclusion.

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

That's it, this answer might lack of code details, but it should help if you encounter same "hide to background when backpress" problem like me, you can get idea of how difficult to achieve expected behavior if you set wrong flag in one step or defined wrong launchMode in one of the activity in manifest.

这篇关于重新排序前后后如何修复应用程序进入后台的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆