一键退出App方法合集

一键退出App相信是很多Android开发者都需要去实现的需求,但到底该如何干净利索地实现它呢?来吧,撸一个试试。

首先需要明确的一点是,完全退出App本质来讲分为两个部分。

  1. 关闭该App所有的Activity。

  2. 结束该App的进程。

接下来我们就分别实现这两个部分。

关闭所有Activity

第一步,我们需要关闭所有的Activity。

1.Activity启动模式

Activity启动模式详解中,我们详细讲解了Activity的启动模式,还不熟悉的小伙伴可以先看一下这篇文章。

首先我们把App的入口Activity采用SingleTask启动模式,或者加上标记Intent.FLAG_ACTIVITY_CLEAR_TOP。

当需要退出App时,直接启动App入口的Activity。因为该Acitivity是SingleTask模式,所以系统会帮助我们将该Activity上面的其他Activity全部关闭移除,并把该Activity放置在栈顶。

1
2
3
4
5
6
@Override
private void exitApp() {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("exitApp", true);
context.startActivity(intent);
}

接着系统会调用该Activity的onNewIntent()方法,所以我们再在这个方法里判断是否有退出App的标识,如果有则关闭自身。

1
2
3
4
5
6
7
8
9
10
11
12
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent != null) {
// 判断是否退出App的标识
boolean isExitApp = intent.getBooleanExtra("exitApp", false);
if (isExitApp) {
// 关闭自身
this.finish();
}
}
}

这种方法使用简单便捷。但是必须要规定App入口的Activity采用SingleTask模式,而且如果App里有多任务栈(SingleInstance模式启动),就无能为力了。

2.系统任务栈

我们可以同过ActivityManager获取当前系统的任务栈,然后把栈内的所有Activity逐个关闭。

1
2
3
4
5
6
7
8
9
10
11
12
@TargetApi(Build.VERSION_CODES.LOLLIPOP)

// 1. 获取ActivityManager
ActivityManager activityManager = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);

// 2. 获取任务栈
List<ActivityManager.AppTask> appTaskList = activityManager.getAppTasks();

// 3. 逐个关闭Activity
for (ActivityManager.AppTask appTask : appTaskList) {
appTask.finishAndRemoveTask();
}

这种方法使用简单便捷。但是只能在Android 5.0以上使用,而且同样,对多任务栈(SingleInstance模式启动)无能为力。

3.BroadcastReceiver

我们也可以通过广播监听的方式来实现关闭所有Activity。

首先自定义一个广播接收器,专门用来关闭Activity。

1
2
3
4
5
6
7
8
9
10
11
12
public class ExitAppReceiver extends BroadcastReceiver {
private Activity activity;

public ExitAppReceiver(Activity activity){
this.activity = activity;
}

@Override
public void onReceive(Context context, Intent intent) {
activity.finish();
}
}

然后在每个Activity里注册广播接收器,这里也可以用一个BaseActivity来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class BaseActivity extends Activity {

private ExitAppReceiver mExitAppReceiver;

// 在onCreate()中注册广播接收器
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mExitAppReceiver = new ExitAppReceiver(this);
registerReceiver(mExitAppReceiver,new IntentFilter("com.chen.exit"));
}

// 在onDestroy()中注销广播接收器
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mExitAppReceive);
}

最后在需要退出App时,发送广播。

1
context.sendBroadcast(new Intent("com.chen.exit"));

这里需要注意的是,该方法只能实现用户角度上的一键退出。即只能退出所有Activity,但无法再接着下面的退出整个App进程的操作。因为发送广播后,并不能保证在第一时间接收到广播,所以不能直接在发送后关闭整个进程。

这种方法可以实现多任务栈情况下的一键退出,但需要在每个Activity里注册广播接收器。最关键的是,它无法做到最终终止App进程。

4.重写Application

我们可以在Manifest里配置自定义的Application子类。

1
2
3
4
<application
...
android:name=".MyApplication"
</application>

接着在MyApplication里建立一个Activity的链表结构,来保存正在运行的Activity实例。当需要一键退出时,把链表里的所有Activity实例逐个退出即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class MyApplicaiton extends Application {

// 采用LinkedList,增删速度快
public static LinkedList<Activity> activityLinkedList;

@Override
public void onCreate() {
super.onCreate();

activityLinkedList = new LinkedList<>();

registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
// 在Activity onCreate()时,保存Activity实例到链表
activityLinkedList.add(activity);
}

@Override
public void onActivityDestroyed(Activity activity) {
// 在Activity onDestroyed()时,移除Activity实例
activityLinkedList.remove(activity);
}

@Override
public void onActivityStarted(Activity activity) {
}

@Override
public void onActivityResumed(Activity activity) {
}

@Override
public void onActivityPaused(Activity activity) {
}

@Override
public void onActivityStopped(Activity activity) {
}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
});
}

public void exitApp() {
// 逐个退出Activity
for (Activity activity : activityLinkedList) {
activity.finish();
}
}
}

接着调用一键退出方法。

1
2
3
4
private MyApplicaiton app;

app = (MyApplicaiton) getApplication();
app.exitApp();

该方法同样可以实现多任务栈情况下的一键退出,但它需要Activity经历正常的生命周期,即创建时调用onCreate(),结束时调用onDestroy()。

5.EventBus或者RxBus

我们也可以借助EventBus或者RxBus来实现这个功能,这里以RxBus为例。

首先,在每个Activity的onCreate()方法里注册RxBus,并判断响应动作是否为退出App,如果是则关闭自己。这里要记得要在onDestroy()方法里取消订阅。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class BaseActivity extends Activity {
private Disposable disposable;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 注册RxBus
disposable = RxBus.getInstance().toObservable(String.class)
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
// 判断响应动作
if (s.equals("exitApp")){
finish();
}
}
});
}

// 取消订阅
@Override
protected void onDestroy() {
if (!disposable.isDisposed()){
disposable.dispose();;
}
}

接着在需要退出App时,发送退出事件。

1
RxBus.getInstance().post("exitApp");

如果项目里已经接入有EventBus或RxBus,可以用该方法简单便捷地实现这个功能。当然,如果项目里没有接入,不建议为该功能特地接入。

结束App进程

上面介绍的方法仅仅是用户层面的一键退出,我们应该在所有Activity关闭后,紧接着再结束整个App的进程,实现真正的一键退出。

当然,上面说到了,如果使用BroadcastReceiver方法来关闭所有Activity,就无法再加接下来这一步了。

这里实现方法有两种,不过都非常简单,选择其中任意一种即可。

1
2
3
4
5
//1.killProcess()
android.os.Process.killProcess(android.os.Process.myPid()) ;

//2.System.exit()
System.exit(0);

这里你可能有个疑问,既然这里可以直接关闭App进程,那为什么还要第一步关闭所有Activity呢?

那我们就做一个实验,先逐个启动ActivityA,ActivityB和ActivityC,接着在ActivityC里调用结束App进程的方法。

我们会发现进程先结束了,接着又重新开启,启动ActivityA和ActivityB。

因为Android中的ActivityManager会时刻监听着进程,如果发现进程被非正常结束,它会去尝试重启这个进程。

总结

至此,一键退出App的所有方法你都应该掌握啦。在项目里根据实际情况,选择最适合的那一种吧。

Chen wechat
欢迎扫描二维码,订阅我的博客公众号MiracleChen