当活动被破坏时,活动背叛的不当行为

时间:2021-06-15 21:12:05

I have two activities; let's say A and B. In activity A there is a broadcast receiver registered that listens for a particular event which will finish activity A. I am registering the broadcast receiver in onCreate(), and destroying it in onDestroy() of activity A.

我有两个活动;让我们说A和B.在活动A中,有一个广播接收器注册了侦听将完成活动A的特定事件。我在onCreate()中注册广播接收器,并在活动A的onDestroy()中销毁它。

For simplicity, there is one button in activity B named "Destroy Activity A". When a user clicks on button, activity A should be destroyed.

为简单起见,活动B中有一个名为“销毁活动A”的按钮。当用户点击按钮时,应销毁活动A.

Normally all of this is running smoothly without any issues,but the problem occurs in following scenarios:

通常所有这些都运行顺利,没有任何问题,但问题出现在以下场景中:

1) Suppose I am in activity B and i press the Home key to move the application to the background then if i use other resource-heavy applications, Android system will kill my application to free memory. Then If I open my application from recent tasks, activity B will be resumed, and it's onCreate(), onResume() etc method will be called. Now I press button to destroy activity A, but activity A has already been destroyed, so activity A's onCreate(), onResume() etc methods will not be called until and unless i go to activity A by pressing the back button. Thus broadcast receiver is not registered to listen for the event.

1)假设我在活动B中,我按Home键将应用程序移动到后台然后如果我使用其他资源繁重的应用程序,Android系统将杀死我的应用程序以释放内存。然后,如果我从最近的任务中打开我的应用程序,将恢复活动B,并且将调用onCreate(),onResume()等方法。现在我按下按钮来销毁活动A,但活动A已被销毁,因此活动A的onCreate(),onResume()等方法将不会被调用,除非我按下后退按钮进入活动A.因此,广播接收器未注册以监听事件。

2) The same problem will arise when user has selected "Don't keep activities" from Developer options in the device's settings.

2)当用户在设备的设置中从Developer选项中选择“Do not keep activities”时,会出现同样的问题。

I have been looking to solve this issue for a long time, but i am unable to find a proper answer. What is the best way to handle this scenario? Is this an Android bug? There should be some solution for this issue.

我一直在寻找解决这个问题很长一段时间,但我无法找到合适的答案。处理此方案的最佳方法是什么?这是Android的错误吗?这个问题应该有一些解决方案。

Please help me.

请帮帮我。

7 个解决方案

#1


3  

This cannot be fixed while keeping your current broadcast logic.

在保持当前广播逻辑的同时无法修复此问题。

Killing activities from the backstack, imo, is not a correct approach. You should strongly consider changing the logic of your navigation.

从后台堆栈杀死imo的活动并不是一种正确的方法。您应该强烈考虑更改导航的逻辑。

But if your project is big and time is a problem, and refactoring is out of the question, A.J. 's approach works, but you mentioned that you have lots of activities that needs to be killed, his solution becomes very tricky to implement.

但是如果你的项目很大并且时间问题,那么重构是不可能的,A.J。方法有效,但你提到你有很多需要被杀死的活动,他的解决方案变得非常棘手。

What I suggest is the following. This might not be the best idea, but I cannot think of another. So maybe that could help.

我建议的是以下内容。这可能不是最好的主意,但我想不到另一个。所以也许这可能有所帮助。

You should have the following:

你应该有以下几点:

  • A Base Activity for all your activities.
  • 适用于所有活动的基本活动。

  • A ArrayList<String> activitiesToKill object at the application level. (If you did not extend Application you can have it as static variable
  • 应用程序级别的ArrayList activitiesToKill对象。 (如果没有扩展Application,可以将它作为静态变量

First we have to make sure that the activitiesToKill is not lost when the OS kills the app in low memory. In the BaseActivity we save the list during onSaveInstanceState and restore it in the onRestoreInstanceState

首先,我们必须确保当操作系统在低内存中杀死应用程序时,eventsToKill不会丢失。在BaseActivity中,我们在onSaveInstanceState期间保存列表并在onRestoreInstanceState中恢复它

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("activitiesToKill", activitiesToKill);
}

private void onRestoreInstanceState(Bundle state) {
    if (state != null) {
        activitiesToKill = (ArrayList<String>) state.getSerializable("activitiesToKill");
    super.onRestoreInstanceState(state); 
}

}

The idea here is to save which activities should be killed in the list, by using their name.

这里的想法是通过使用他们的名字来保存列表中应该杀死的活动。

The logic is as follow:

逻辑如下:

Let's say you have Activities A, B, C, D and E

假设您有活动A,B,C,D和E.

From Activity E, you press the button and you want to kill B and D

从活动E,你按下按钮,你想要杀死B和D.

When you press the Button in E, you add the names of B and D to the activitiesToKill object.

按E中的按钮时,将B和D的名称添加到activitiesToKill对象中。

activitiesToKill.add(B.class.getSimpleName()
activitiesToKill.add(D.class.getSimpleName()

In the onCreate method of the BaseActivity, we have to check if the

在BaseActivity的onCreate方法中,我们必须检查是否

if(savedInstanceState != null)
{
    //The activity is being restored. We check if the it is in the lest to Kill and we finish it                
    if(activitiesToKill.contains(this.getClass().getSimpleName()))
    {
        activitiesToKill.remove(this.getClass().getSimpleName())
        finish();
    }
}

Make sure to remove the name of the activity if it is killed through the broadcast.

如果通过广播将其杀死,请确保删除活动的名称。

So basically this is what happens in every scenario.

所以基本上这就是每个场景中发生的事情。

If the app is running normally, and you click the button, the broadcast gets sent and B and D will get killed. Make sure to remove B and D from the activitiesToKill

如果应用程序正常运行,并且您单击按钮,广播将被发送,B和D将被杀死。确保从activitiesToKill中删除B和D.

If the app was killed and restored, you press the button, the broadcast will have no effect, but you have added B and D to the activitiesToKill object. So when you click back, the activity is created and the savedInstanceState is not null, the activity is finished.

如果应用程序被杀死并恢复,您按下按钮,广播将无效,但您已将B和D添加到activitiesToKill对象。因此,当您单击返回时,将创建活动并且savedInstanceState不为null,活动已完成。

This approach consider that activity E knows which activities it has to kill.

这种方法认为活动E知道它必须杀死哪些活动。

In case you DON'T know which activities to kill from E, you have to modify this logic slightly:

如果您不知道从E中杀死哪些活动,您必须稍微修改此逻辑:

Instead of using an ArrayList use a HashMap<String, bool>

而不是使用ArrayList使用HashMap ,bool>

When Activity B is created, it will register it self to the hashmap:

创建活动B时,它会将其自己注册到hashmap:

activitiesToKill.put(this.class.getSimpleName(), false)

Then from Activity E, all you have to do is set all the entries to true

然后从活动E,您所要做的就是将所有条目设置为true

Then in the on create of the base activity you have to check if this activity is registered in the activitiesToKill (the hashmap contains the key) AND the boolean is true you kill it (don't forget to return it to false, or remove the key)

然后在创建基本活动时,你必须检查这个活动是否在activitiesToKill中注册(hashmap包含键)并且boolean为true你杀了它(不要忘记将它返回false,或者删除键)

This ensure that each activity register itself to the HashMap and Activity E doesn't have top know all the activities to kill. And don't forget to remove them in case the broadcast kills them.

这样可以确保每个活动都将自己注册到HashMap,而活动E没有知道所有要杀死的活动。并且不要忘记删除它们以防广播杀死它们。

This approach also ensure that the activity is not killed when opened normally from an intent because in that case onSaveInstanceState would be null in the onCreate, so nothing will happen.

这种方法还确保在从intent中正常打开时不会杀死活动,因为在那种情况下onSaveInstanceState在onCreate中将为null,因此不会发生任何事情。

More advanced checks can be accomplished in case you have groups of activities that needs to be terminated through different conditions (not only a button click) so you can have a HashMap of a HashMap to divide them in categories.

如果您有一组需要通过不同条件(不仅仅是单击按钮)终止的活动,则可以完成更高级的检查,这样您就可以使用HashMap的HashMap将它们分类。

Also note, that you can use getName instead of getSimpleName if you have multiple activities with same name but different bundles.

另请注意,如果您有多个具有相同名称但不同的包的活动,则可以使用getName而不是getSimpleName。

I hope my explanation is clear enough as I wrote it from my head, let me know if any area is not clear.

我希望我的解释很清楚,因为我是从头脑中写下来的,如果有任何方面不清楚,请告诉我。

Best of luck

祝你好运

#2


6  

If your Activity A has destroyed by Android OS itself then there are no way to track.

如果您的活动A已被Android操作系统本身销毁,则无法跟踪。

Some people has suggested to track that Activity A by listning event in onDestroy method BUT if your Activity killed by system OS then note here it wont call those method .

有些人建议通过在onDestroy方法中列出事件来跟踪活动A,但如果您的活动被系统操作系统杀死,那么请注意这里它不会调用这些方法。

#3


0  

I don't know if it's possible to handle this on a "proper" way.

我不知道是否有可能以“正确”的方式处理这个问题。

What it comes to my mind, is to flag the A activity in some way. You can't use startActivityForResult() because you will receive the result before onResume() is called i.e. UI was already inflated.

我想到的是以某种方式标记A活动。您不能使用startActivityForResult(),因为您将在调用onResume()之前收到结果,即UI已经膨胀。

If you using an Otto, you could try with a sticky event. Otherwise you will need a singleton to handle the flag or save it to shared preferences.

如果您使用Otto,则可以尝试使用粘性事件。否则,您将需要一个单例来处理该标志或将其保存到共享首选项。

You will have to check that flag on your onCreate() method before calling setContentView(), if the flag is true just finish the activity.

在调用setContentView()之前,您必须在onCreate()方法上检查该标志,如果该标志为true,则只需完成活动。

#4


0  

With the information you have given, how about you register the broadcast in onCreate of Activity B after checking if its registered already or not. If onDestroy of Activity A has been called in either of the scenarios you have mentioned, then the deregister of the Broadcast would have been called. So in that case, you can register your Broadcast in onCreate of Activity B, so that you can listen to it, even if you have only the Activity B in your backstack.

根据您提供的信息,您在检查其是否已注册后,如何在活动B的onCreate中注册广播。如果在您提到的任一场景中调用了活动A的onDestroy,那么将调用广播的注销。因此,在这种情况下,您可以在活动B的onCreate中注册您的广播,这样即使您的背书中只有活动B,您也可以收听它。

#5


0  

Have you considered using Sticky Broadcast? Also you can register your receiver on application level (in manifest) and listen to this event regardless of Activity A state.

你考虑过使用Sticky Broadcast吗?此外,您可以在应用程序级别(在清单中)注册您的接收器,并监听此事件,无论活动A状态如何。

But, like already said Youssef, killing activities from the backstack is not a correct approach. You should strongly consider changing the logic of your navigation.

但是,就像Youssef已经说过的那样,从后台进行杀戮活动并不是一种正确的做法。您应该强烈考虑更改导航的逻辑。

#6


0  

One of the main rules with Activities is you can't rely on any activity being alive except the foreground activity. The thing you're trying to do with broadcasts has nothing to do with back stack -- back stack doesn't guarantee all activities are alive at all times, but it will make sure they're recreated when it's time to go foreground.

活动的主要规则之一是除了前台活动之外,您不能依赖任何活动。您尝试使用广播进行的操作与后台堆栈无关 - 后台堆栈并不能保证所有活动始终处于活动状态,但它会确保它们在前景时重新创建。

In your example (if my understanding of what you're aiming to do) you need to navigate to something underneath A -- say, Activity Z, and the stack looks like this: Z-A-[B]. There's normal course of events where you hit back and it takes you to A, then after another hit -- to Z but in a certain case (say pressing a button) you want to move back to Z bypassing A -- this is a classic case to use FLAG_ACTIVITY_CLEAR_TOP and launch Z explicitly:

在你的例子中(如果我理解你的目标是什么)你需要导航到A下面的东西 - 例如,活动Z,并且堆栈看起来像这样:Z-A- [B]。有正常的事件,你回击它,它会带你到A,然后在另一次击中 - 到Z但在某种情况下(比如按一个按钮)你想要回到Z绕过A - 这是一个经典使用FLAG_ACTIVITY_CLEAR_TOP并明确启动Z的情况:

Intent intent = new Intent(this, ActivityZ.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

This will finish both B and A, and deliver the intent to Z. You will, probably also need the FLAG_ACTIVITY_SINGLE_TOP flag, pay close attention to the description of FLAG_ACTIVITY_CLEAR_TOP, there's some trickery you should consider.

这将完成B和A,并将意图传递给Z.您可能还需要FLAG_ACTIVITY_SINGLE_TOP标志,密切关注FLAG_ACTIVITY_CLEAR_TOP的描述,您应该考虑一些技巧。

#7


-1  

Many solutions came to my mind but as you have not provided much information about your app, so I think this should work in general.

我想到了许多解决方案,但由于您没有提供有关您的应用程序的大量信息,所以我认为这应该可以正常工作。

Instead of firing a broadcast to kill Activity A, just execute the following code when the "Kill Activity A" button is pressed in Activity B.

而不是触发广播来杀死活动A,只需在活动B中按下“杀死活动A”按钮时执行以下代码。

        Intent intent = new Intent(getApplicationContext(),
                ActivityA.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        intent.putExtra("EXIT", true);
        startActivity(intent);

Add the following code in activity A

在活动A中添加以下代码

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    if (intent.getBooleanExtra("EXIT", false)) {
        finish();
    }
}

protected void onCreate(Bundle savedInstanceState) {
    //Ideally, there should not be anything before this
    super.onCreate(savedInstanceState);
    if(getIntent().getBooleanExtra("EXIT", false)){
        finish();
        return;
    }

In the manifest set "singleTop" launch mode for activity A.

在活动A的清单集“singleTop”启动模式中。

<activity
    android:name=".ActivityA"
    ...
    android:launchMode="singleTop" />

This will have the following consequences:

这将产生以下后果:

  • If Activity A is already running it will brought to the front of the activity stack and finished, thus removing it from the stack.
  • 如果活动A已经运行,它将被带到活动堆栈的前面并完成,从而将其从堆栈中移除。

  • If Activity A has been destroyed but still present in the activity stack (to be launched when back button is pressed), it will be started, brought to front and finished, thus removing it from the activity stack.
  • 如果活动A已被销毁但仍存在于活动堆栈中(按下后退按钮时将启动),它将被启动,结束并完成,从而将其从活动堆栈中删除。

  • If Activity A has already has already been destroyed and not present in the activity stack, and you still press the "Remove Activity A" button, it will be started, brought to front and finished.
  • 如果活动A已经被销毁并且不存在于活动堆栈中,并且您仍然按下“删除活动A”按钮,它将被启动,结束并完成。

Generally, you should not see any flicker.

通常,您不应该看到任何闪烁。

Based on this idea, you may build a better performing solution for your particular app. For example, you may use the FLAG_ACTIVITY_CLEAR_TOP and finish the Activity A in onBackPressed() of Activity B.

基于这个想法,您可以为您的特定应用程序构建更好的解决方案。例如,您可以使用FLAG_ACTIVITY_CLEAR_TOP并在活动B的onBackPressed()中完成活动A.

#1


3  

This cannot be fixed while keeping your current broadcast logic.

在保持当前广播逻辑的同时无法修复此问题。

Killing activities from the backstack, imo, is not a correct approach. You should strongly consider changing the logic of your navigation.

从后台堆栈杀死imo的活动并不是一种正确的方法。您应该强烈考虑更改导航的逻辑。

But if your project is big and time is a problem, and refactoring is out of the question, A.J. 's approach works, but you mentioned that you have lots of activities that needs to be killed, his solution becomes very tricky to implement.

但是如果你的项目很大并且时间问题,那么重构是不可能的,A.J。方法有效,但你提到你有很多需要被杀死的活动,他的解决方案变得非常棘手。

What I suggest is the following. This might not be the best idea, but I cannot think of another. So maybe that could help.

我建议的是以下内容。这可能不是最好的主意,但我想不到另一个。所以也许这可能有所帮助。

You should have the following:

你应该有以下几点:

  • A Base Activity for all your activities.
  • 适用于所有活动的基本活动。

  • A ArrayList<String> activitiesToKill object at the application level. (If you did not extend Application you can have it as static variable
  • 应用程序级别的ArrayList activitiesToKill对象。 (如果没有扩展Application,可以将它作为静态变量

First we have to make sure that the activitiesToKill is not lost when the OS kills the app in low memory. In the BaseActivity we save the list during onSaveInstanceState and restore it in the onRestoreInstanceState

首先,我们必须确保当操作系统在低内存中杀死应用程序时,eventsToKill不会丢失。在BaseActivity中,我们在onSaveInstanceState期间保存列表并在onRestoreInstanceState中恢复它

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("activitiesToKill", activitiesToKill);
}

private void onRestoreInstanceState(Bundle state) {
    if (state != null) {
        activitiesToKill = (ArrayList<String>) state.getSerializable("activitiesToKill");
    super.onRestoreInstanceState(state); 
}

}

The idea here is to save which activities should be killed in the list, by using their name.

这里的想法是通过使用他们的名字来保存列表中应该杀死的活动。

The logic is as follow:

逻辑如下:

Let's say you have Activities A, B, C, D and E

假设您有活动A,B,C,D和E.

From Activity E, you press the button and you want to kill B and D

从活动E,你按下按钮,你想要杀死B和D.

When you press the Button in E, you add the names of B and D to the activitiesToKill object.

按E中的按钮时,将B和D的名称添加到activitiesToKill对象中。

activitiesToKill.add(B.class.getSimpleName()
activitiesToKill.add(D.class.getSimpleName()

In the onCreate method of the BaseActivity, we have to check if the

在BaseActivity的onCreate方法中,我们必须检查是否

if(savedInstanceState != null)
{
    //The activity is being restored. We check if the it is in the lest to Kill and we finish it                
    if(activitiesToKill.contains(this.getClass().getSimpleName()))
    {
        activitiesToKill.remove(this.getClass().getSimpleName())
        finish();
    }
}

Make sure to remove the name of the activity if it is killed through the broadcast.

如果通过广播将其杀死,请确保删除活动的名称。

So basically this is what happens in every scenario.

所以基本上这就是每个场景中发生的事情。

If the app is running normally, and you click the button, the broadcast gets sent and B and D will get killed. Make sure to remove B and D from the activitiesToKill

如果应用程序正常运行,并且您单击按钮,广播将被发送,B和D将被杀死。确保从activitiesToKill中删除B和D.

If the app was killed and restored, you press the button, the broadcast will have no effect, but you have added B and D to the activitiesToKill object. So when you click back, the activity is created and the savedInstanceState is not null, the activity is finished.

如果应用程序被杀死并恢复,您按下按钮,广播将无效,但您已将B和D添加到activitiesToKill对象。因此,当您单击返回时,将创建活动并且savedInstanceState不为null,活动已完成。

This approach consider that activity E knows which activities it has to kill.

这种方法认为活动E知道它必须杀死哪些活动。

In case you DON'T know which activities to kill from E, you have to modify this logic slightly:

如果您不知道从E中杀死哪些活动,您必须稍微修改此逻辑:

Instead of using an ArrayList use a HashMap<String, bool>

而不是使用ArrayList使用HashMap ,bool>

When Activity B is created, it will register it self to the hashmap:

创建活动B时,它会将其自己注册到hashmap:

activitiesToKill.put(this.class.getSimpleName(), false)

Then from Activity E, all you have to do is set all the entries to true

然后从活动E,您所要做的就是将所有条目设置为true

Then in the on create of the base activity you have to check if this activity is registered in the activitiesToKill (the hashmap contains the key) AND the boolean is true you kill it (don't forget to return it to false, or remove the key)

然后在创建基本活动时,你必须检查这个活动是否在activitiesToKill中注册(hashmap包含键)并且boolean为true你杀了它(不要忘记将它返回false,或者删除键)

This ensure that each activity register itself to the HashMap and Activity E doesn't have top know all the activities to kill. And don't forget to remove them in case the broadcast kills them.

这样可以确保每个活动都将自己注册到HashMap,而活动E没有知道所有要杀死的活动。并且不要忘记删除它们以防广播杀死它们。

This approach also ensure that the activity is not killed when opened normally from an intent because in that case onSaveInstanceState would be null in the onCreate, so nothing will happen.

这种方法还确保在从intent中正常打开时不会杀死活动,因为在那种情况下onSaveInstanceState在onCreate中将为null,因此不会发生任何事情。

More advanced checks can be accomplished in case you have groups of activities that needs to be terminated through different conditions (not only a button click) so you can have a HashMap of a HashMap to divide them in categories.

如果您有一组需要通过不同条件(不仅仅是单击按钮)终止的活动,则可以完成更高级的检查,这样您就可以使用HashMap的HashMap将它们分类。

Also note, that you can use getName instead of getSimpleName if you have multiple activities with same name but different bundles.

另请注意,如果您有多个具有相同名称但不同的包的活动,则可以使用getName而不是getSimpleName。

I hope my explanation is clear enough as I wrote it from my head, let me know if any area is not clear.

我希望我的解释很清楚,因为我是从头脑中写下来的,如果有任何方面不清楚,请告诉我。

Best of luck

祝你好运

#2


6  

If your Activity A has destroyed by Android OS itself then there are no way to track.

如果您的活动A已被Android操作系统本身销毁,则无法跟踪。

Some people has suggested to track that Activity A by listning event in onDestroy method BUT if your Activity killed by system OS then note here it wont call those method .

有些人建议通过在onDestroy方法中列出事件来跟踪活动A,但如果您的活动被系统操作系统杀死,那么请注意这里它不会调用这些方法。

#3


0  

I don't know if it's possible to handle this on a "proper" way.

我不知道是否有可能以“正确”的方式处理这个问题。

What it comes to my mind, is to flag the A activity in some way. You can't use startActivityForResult() because you will receive the result before onResume() is called i.e. UI was already inflated.

我想到的是以某种方式标记A活动。您不能使用startActivityForResult(),因为您将在调用onResume()之前收到结果,即UI已经膨胀。

If you using an Otto, you could try with a sticky event. Otherwise you will need a singleton to handle the flag or save it to shared preferences.

如果您使用Otto,则可以尝试使用粘性事件。否则,您将需要一个单例来处理该标志或将其保存到共享首选项。

You will have to check that flag on your onCreate() method before calling setContentView(), if the flag is true just finish the activity.

在调用setContentView()之前,您必须在onCreate()方法上检查该标志,如果该标志为true,则只需完成活动。

#4


0  

With the information you have given, how about you register the broadcast in onCreate of Activity B after checking if its registered already or not. If onDestroy of Activity A has been called in either of the scenarios you have mentioned, then the deregister of the Broadcast would have been called. So in that case, you can register your Broadcast in onCreate of Activity B, so that you can listen to it, even if you have only the Activity B in your backstack.

根据您提供的信息,您在检查其是否已注册后,如何在活动B的onCreate中注册广播。如果在您提到的任一场景中调用了活动A的onDestroy,那么将调用广播的注销。因此,在这种情况下,您可以在活动B的onCreate中注册您的广播,这样即使您的背书中只有活动B,您也可以收听它。

#5


0  

Have you considered using Sticky Broadcast? Also you can register your receiver on application level (in manifest) and listen to this event regardless of Activity A state.

你考虑过使用Sticky Broadcast吗?此外,您可以在应用程序级别(在清单中)注册您的接收器,并监听此事件,无论活动A状态如何。

But, like already said Youssef, killing activities from the backstack is not a correct approach. You should strongly consider changing the logic of your navigation.

但是,就像Youssef已经说过的那样,从后台进行杀戮活动并不是一种正确的做法。您应该强烈考虑更改导航的逻辑。

#6


0  

One of the main rules with Activities is you can't rely on any activity being alive except the foreground activity. The thing you're trying to do with broadcasts has nothing to do with back stack -- back stack doesn't guarantee all activities are alive at all times, but it will make sure they're recreated when it's time to go foreground.

活动的主要规则之一是除了前台活动之外,您不能依赖任何活动。您尝试使用广播进行的操作与后台堆栈无关 - 后台堆栈并不能保证所有活动始终处于活动状态,但它会确保它们在前景时重新创建。

In your example (if my understanding of what you're aiming to do) you need to navigate to something underneath A -- say, Activity Z, and the stack looks like this: Z-A-[B]. There's normal course of events where you hit back and it takes you to A, then after another hit -- to Z but in a certain case (say pressing a button) you want to move back to Z bypassing A -- this is a classic case to use FLAG_ACTIVITY_CLEAR_TOP and launch Z explicitly:

在你的例子中(如果我理解你的目标是什么)你需要导航到A下面的东西 - 例如,活动Z,并且堆栈看起来像这样:Z-A- [B]。有正常的事件,你回击它,它会带你到A,然后在另一次击中 - 到Z但在某种情况下(比如按一个按钮)你想要回到Z绕过A - 这是一个经典使用FLAG_ACTIVITY_CLEAR_TOP并明确启动Z的情况:

Intent intent = new Intent(this, ActivityZ.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

This will finish both B and A, and deliver the intent to Z. You will, probably also need the FLAG_ACTIVITY_SINGLE_TOP flag, pay close attention to the description of FLAG_ACTIVITY_CLEAR_TOP, there's some trickery you should consider.

这将完成B和A,并将意图传递给Z.您可能还需要FLAG_ACTIVITY_SINGLE_TOP标志,密切关注FLAG_ACTIVITY_CLEAR_TOP的描述,您应该考虑一些技巧。

#7


-1  

Many solutions came to my mind but as you have not provided much information about your app, so I think this should work in general.

我想到了许多解决方案,但由于您没有提供有关您的应用程序的大量信息,所以我认为这应该可以正常工作。

Instead of firing a broadcast to kill Activity A, just execute the following code when the "Kill Activity A" button is pressed in Activity B.

而不是触发广播来杀死活动A,只需在活动B中按下“杀死活动A”按钮时执行以下代码。

        Intent intent = new Intent(getApplicationContext(),
                ActivityA.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        intent.putExtra("EXIT", true);
        startActivity(intent);

Add the following code in activity A

在活动A中添加以下代码

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    if (intent.getBooleanExtra("EXIT", false)) {
        finish();
    }
}

protected void onCreate(Bundle savedInstanceState) {
    //Ideally, there should not be anything before this
    super.onCreate(savedInstanceState);
    if(getIntent().getBooleanExtra("EXIT", false)){
        finish();
        return;
    }

In the manifest set "singleTop" launch mode for activity A.

在活动A的清单集“singleTop”启动模式中。

<activity
    android:name=".ActivityA"
    ...
    android:launchMode="singleTop" />

This will have the following consequences:

这将产生以下后果:

  • If Activity A is already running it will brought to the front of the activity stack and finished, thus removing it from the stack.
  • 如果活动A已经运行,它将被带到活动堆栈的前面并完成,从而将其从堆栈中移除。

  • If Activity A has been destroyed but still present in the activity stack (to be launched when back button is pressed), it will be started, brought to front and finished, thus removing it from the activity stack.
  • 如果活动A已被销毁但仍存在于活动堆栈中(按下后退按钮时将启动),它将被启动,结束并完成,从而将其从活动堆栈中删除。

  • If Activity A has already has already been destroyed and not present in the activity stack, and you still press the "Remove Activity A" button, it will be started, brought to front and finished.
  • 如果活动A已经被销毁并且不存在于活动堆栈中,并且您仍然按下“删除活动A”按钮,它将被启动,结束并完成。

Generally, you should not see any flicker.

通常,您不应该看到任何闪烁。

Based on this idea, you may build a better performing solution for your particular app. For example, you may use the FLAG_ACTIVITY_CLEAR_TOP and finish the Activity A in onBackPressed() of Activity B.

基于这个想法,您可以为您的特定应用程序构建更好的解决方案。例如,您可以使用FLAG_ACTIVITY_CLEAR_TOP并在活动B的onBackPressed()中完成活动A.