重新排序前后后如何修复应用程序进入后台 [英] How to fix app go to background after reorder to front and back
问题描述
我目前设法允许用户在两个不同的活动组(让我们说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
?
我注意到它仅在同一类中发生(B
和B2
是同一类),如果我使用B
和C
,则不会出现此类问题,我想知道背后的原因是什么.
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
也是重现它的关键.
我试图使用应用程序级别的自定义实例列表来检测B2
的onPause()
和isFinishing()
以及startActivty()
的B
,但是即使它总是会调用B
的onCreate()
尽管使用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,将它放在setContentView
和finish()
/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屋!