Android: 清除活动栈

146

我在我的应用中有几个活动,并且流程非常复杂。当我点击注销时,应用程序将导航到登录屏幕,用户可以通过取消按钮退出(调用system.exit(0)

当我按下返回按钮或退出按钮时,系统会从堆栈中调用一个活动 :( 当我到达登录屏幕时,如何清除所有活动?调用finish()并不实际,因为有很多活动,其中一些活动在处于活动状态时不应关闭,例如调用本地相机的活动。

validateuser logoutuser = new validateuser();
logoutuser.logOut();
Intent loginscreen = new Intent(homepage.this, Login2.class);
(homepage.this).finish();
loginscreen.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(loginscreen);

1
请查看此链接...https://dev59.com/flTTa4cB1Zd3GeqPvL1e#5140545 - xydev
可能是Android:清除后退堆栈的重复问题。 - Mehdi Dehghani
11个回答

369

大多数人都是错的。如果您想关闭现有的活动堆栈并创建新的根堆栈,而不管其中有什么内容,则正确的标志集为以下内容:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

文档中的说明:

public static final int FLAG_ACTIVITY_CLEAR_TASK
自 API 级别 11 新增

如果将此标志设置在传递给 Context.startActivity() 的 Intent 中,这将导致与该活动关联的任何现有任务在启动活动之前被清除。也就是说,活动成为空任务的新根,任何旧活动都将被结束。这只能与 FLAG_ACTIVITY_NEW_TASK 结合使用。


完美地工作了。谢谢。奇怪的是,即使minSDK=9,也没有出现错误。 - Mahm00d
坦白说,我从来没有使用过这个功能,即崩溃后恢复等,而是更专注于修复导致崩溃的问题。 - Cynichniy Bandera
同样的功能也可以通过支持库中的IntentCompat.makeRestartActivityTask来实现。 - sealskej
仅添加这两个标志会留下活动堆栈轨迹(从上一个活动开始),然后添加Intent.FLAG_ACTIVITY_CLEAR_TOP,它只是重新启动应用程序,然后完全退出。我没有明确地为活动添加任何标志。可能出了什么问题? - Farid
无法与 singleInstance launchMode 活动一起使用发送。 - TheRealChx101
1
其中一个最好的开头:“你们大多数人都错了。” - nibbana

30

当您在最后一个活动上调用 startActivity 时,您总是可以在该意图上使用

Intent.FLAG_ACTIVITY_CLEAR_TOP

作为标记。

有关此标志的更多信息,请在这里阅读。


那也没有帮助。它只是打开了一个没有以finish()结束的活动 :( - Jay Mayu
7
感谢您提供正确的资源。我的错误是关闭了登录活动(Login activity)。我不应该这样做。当第一次加载该活动时,不要关闭它。因此,当我使用Clear_top标志(call it back using Clear_top flag)调用它时,登录活动会清除所有在其之上的活动。由于登录(Login)是第一个入口活动,因此它会清除在其之后启动的所有活动。所以 Bingo!它成功了 :) - Jay Mayu
13
根据文档,FLAG_ACTIVITY_CLEAR_TOP 只会清除堆栈,如果特定的活动 "已经在当前任务中运行"。 - AlikElzin-kilaka
@AlikElzin-kilaka 很好的提醒。如果活动尚未运行,有什么解决方案! - Muhammad Babar
@Umka 在这种情况下,你应该链接。"below" 现在就回答了我的排序变化。 - David Olsson
显示剩余3条评论

16

这里有一个简单的帮助方法,可以从API 4级一直工作到当前版本17,用于启动一个新活动并将其作为新的顶部活动:

static void startNewMainActivity(Activity currentActivity, Class<? extends Activity> newTopActivityClass) {
    Intent intent = new Intent(currentActivity, newTopActivityClass);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        intent.addFlags(0x8000); // equal to Intent.FLAG_ACTIVITY_CLEAR_TASK which is only available from API level 11
    currentActivity.startActivity(intent);
}

从当前活动中这样调用:

startNewMainActivity(this, MainActivity.class);

1
你难道不能直接使用intent.addFlags(0x8000)来简化操作吗? - Davor
由于这个标志是在Honeycomb中首次引入的,我不知道它对早期版本可能产生什么影响。所以,这只是我采取的预防措施。但我想删除条件应该不是问题。 - whlk
1
如果API级别小于11,则需要添加该标志,然后您需要执行Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB,否则intent.addFlags(0x8000);将永远不会被添加。 - Straw Hat
我让用户通过意图接连进行许多活动。为了确保应用程序不会在堆栈中拥有太多活动而崩溃,我需要做些什么吗?谢谢! - Ruchir Baronia

11

使用以下代码清除活动的后退状态:

Intent intent = new Intent(Your_Current_Activity.this, Your_Destination_Activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

完成


我正在通过意图让用户依次执行许多活动。我需要做些什么来确保应用程序不会因为堆栈中有太多活动而崩溃吗?谢谢! - Ruchir Baronia
@RuchirBaronia,如果你从A到B再到C,然后到D、E、F、G、H,现在从H到I,你写我的代码,那么我将成为最后一个活动,之后你按返回按钮应用程序将关闭,因为应用程序没有后退状态活动,希望这能帮到你。 - Hiren Patel
我需要这么做吗?如果我从来不清理活动栈会发生什么? - Ruchir Baronia
@RuchirBaronia,Backpress:H -> G -> F -> E -> D -> C -> B -> A - Hiren Patel
但有时调用新活动时会显示白屏。如何解决? - Sagar
添加 Intent.FLAG_ACTIVITY_CLEAR_TOP 标志会重启应用程序,然后完全退出。虽然我没有显式地为活动添加任何标志,但可能存在什么问题呢? - Farid

4
Intent intent = new Intent(LoginActivity.this, Home.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  //It is use to finish current activity
startActivity(intent);
this.finish();

2
为什么你同时使用 this.finish()setFlags() 来清除当前活动? - Sagar

4
这个决定很好:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

但是新的活动启动需要很长时间,有时会看到白屏。如果这很关键,请使用以下解决方法:

public class BaseActivity extends AppCompatActivity {

    private static final String ACTION_FINISH = "action_finish";

    private BroadcastReceiver finisBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        registerReceiver(finisBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                finish();
            }
        }, new IntentFilter(ACTION_FINISH));
    }

    public void clearBackStack() {
        sendBroadcast(new Intent(ACTION_FINISH));
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(finisBroadcastReceiver);
        super.onDestroy();
    }
}

如何使用它:
public class ActivityA extends BaseActivity {

    // Click any button
    public void startActivityB() {
        startActivity(new Intent(this, ActivityB.class));
        clearBackStack();
    }
}

缺点:必须在堆栈上关闭的所有活动都必须扩展BaseActivity。


4

使用 Kotlin:

您可以直接使用 setter 方法设置标志。 在 Kotlin 中,or 是 Java 按位或 |替代品

intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK

如果您计划经常使用此功能,请创建一个Intent扩展函数。

fun Intent.clearStack() {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

你可以在启动 intent 之前直接调用此函数。
intent.clearStack()

3

我注意到你要求一个不依赖于finish()的解决方案,但我想这个解决方案可能仍有帮助。

我使用了一个静态类变量来跟踪是否抛出了退出标志,该变量在整个应用程序生命周期内都存在。在每个相关的活动的onResume()中使用。

@Override
public void onResume() {
    super.onResume();
    if (ExitHelper.isExitFlagRaised) {
        this.finish();
    }
}

ExitHelper类
public class ExitHelper {
    public static boolean isExitFlagRaised = false;
}

假设在主活动(mainActivity)中,用户按下一个退出按钮 - 您可以设置ExitHelper.isExitFlagRaised = true;然后finish()。此后,其他自动恢复的相关活动也将被结束。

如果我在MainActivity的onResume()中使用代码,然后从第二个活动返回到MainActivity,会发生什么? - Mithu

3
在我的情况下,LoginActivity也被关闭了。因此,
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK

虽然这并没有什么帮助。

不过,设置

Intent.FLAG_ACTIVITY_NEW_TASK

帮助过我。

我正在通过意图让用户依次执行许多活动。我需要做些什么来确保应用程序不会因为堆栈中有太多活动而崩溃吗?谢谢! - Ruchir Baronia

3

对于Xamarin开发者,您可以使用以下内容:

intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接