功能-Android退出应用的方式

Android退出应用的方式

一、容器式

建立一个全局容器,把所有的Activity存储起来,退出时循环遍历finish所有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
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;

public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 添加Activity到堆栈
AtyContainer.getInstance().addActivity(this);
}

@Override
protected void onDestroy() {
super.onDestroy();
// 结束Activity&从栈中移除该Activity
AtyContainer.getInstance().removeActivity(this);
}
}

class AtyContainer {
private AtyContainer() {
}

private static AtyContainer instance = new AtyContainer();
private static List<Activity> activityStack = new ArrayList<Activity>();
public static AtyContainer getInstance() {
return instance;
}

public void addActivity(Activity aty) {
activityStack.add(aty);
}

public void removeActivity(Activity aty) {
activityStack.remove(aty);
}

/**
* 结束所有Activity
*/
public void finishAllActivity() {
for (int i = 0, size = activityStack.size(); i < size; i++) {
if (null != activityStack.get(i)) {
activityStack.get(i).finish();
}
}
activityStack.clear();
}
}

这种方法比较简单, 但是可以看到activityStack持有这Activity的强引用,也就是说当某个Activity异常退出时,activityStack没有及时释放掉引用,就会导致内存问题,接下来我们看一种类似的方式,但是会稍微优雅一点点

二、广播式

通过在BaseActivity中注册一个广播,当退出时发送一个广播,finish退出

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
public class BaseActivity extends Activity {
private static final String EXITACTION = "action.exit";
private ExitReceiver exitReceiver = new ExitReceiver();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter();
filter.addAction(EXITACTION);
registerReceiver(exitReceiver, filter);
}

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

class ExitReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
BaseActivity.this.finish();
}
}
}

三、进程式

通过直接杀死当前应用的进程来结束应用,简单粗暴,而且有(wu)效!

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

System.exit(0);

ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
manager.killBackgroundProcesses(getPackageName());

这三种都能达到同样的效果,但是在模拟器上都会弹出 Unfortunately , XXX has stopped 消息提示框,但确实能退出应用。部分真机直接失效,只能finish当前Activity(比如我手上这台小米note,国产的几款ROM fw层改动太多,使用这种方式需慎重) 。

四、 RS优雅式

什么是RS式呢?即Receiver+singleTask 。我们知道Activity有四种加载模式,而singleTask就是其中的一种,使用这个模式之后,当startActivity时,它先会在当前栈中查询是否存在Activity的实例,如果存在,则将其至于栈顶,并将其之上的所有Activity移除栈。我们打开一个app,首先是一个splash页面,然后会finish掉splash页面。跳转到主页。然后会在主页进行N次的跳转,期间会产生数量不定的Activity,有的被销毁,有的驻留在栈中,但是栈底永远是我们的HomeActivity。这样就让问题变得简单很多了。我们只需两步操作即可优雅的实现app的退出。

1、在HomeActivity注册一个退出广播,和第二个广播式一样,但是这里只需要在HomeActivity一个页面注册即可。

2、设置HomeActivity的启动模式为singleTask。

当我们需要退出的时候只需要startActivity(this,HomeActivity,class), 再发送一个退出广播。上面代码首先会把栈中HomeActivity之上的所有Activity移除出栈,然后接到广播finish自己。一切OK ! 没有弹框,不用考虑机型Rom适配。不会有内存问题,就是那么的优雅,简单!

监听app切换前后台

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;

import com.xm597.common.debug.DebugLog;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class ForegroundCallbacks implements Application.ActivityLifecycleCallbacks {
public static final long CHECK_DELAY = 500;
public static final String TAG = ForegroundCallbacks.class.getName();

public interface Listener {
public void onBecameForeground();

public void onBecameBackground();
}

private static ForegroundCallbacks instance;
private boolean foreground = false, paused = true;
private Handler handler = new Handler();
private List<Listener> listeners = new CopyOnWriteArrayList<Listener>();
private Runnable check;

public static ForegroundCallbacks init(Application application) {
if (instance == null) {
instance = new ForegroundCallbacks();
application.registerActivityLifecycleCallbacks(instance);
}
return instance;
}

public static ForegroundCallbacks get(Application application) {
if (instance == null) {
init(application);
}
return instance;
}

public static ForegroundCallbacks get(Context ctx) {
if (instance == null) {
Context appCtx = ctx.getApplicationContext();
if (appCtx instanceof Application) {
init((Application) appCtx);
}
throw new IllegalStateException(
"Foreground is not initialised and " +
"cannot obtain the Application object");
}
return instance;
}

public static ForegroundCallbacks get() {
if (instance == null) {
throw new IllegalStateException(
"Foreground is not initialised - invoke " +
"at least once with parameterised init/get");
}
return instance;
}

public boolean isForeground() {
return foreground;
}

public boolean isBackground() {
return !foreground;
}

public void addListener(Listener listener) {
listeners.add(listener);
}

public void removeListener(Listener listener) {
listeners.remove(listener);
}

@Override
public void onActivityResumed(Activity activity) {
paused = false;
boolean wasBackground = !foreground;
foreground = true;
if (check != null)
handler.removeCallbacks(check);
if (wasBackground) {
DebugLog.log("went foreground");

for (Listener l : listeners) {
try {
l.onBecameForeground();
} catch (Exception exc) {
DebugLog.log("Listener threw exception!:" + exc.toString());
}
}
} else {
DebugLog.log("still foreground");
}
}

@Override
public void onActivityPaused(Activity activity) {
paused = true;
if (check != null)
handler.removeCallbacks(check);
handler.postDelayed(check = new Runnable() {
@Override
public void run() {
if (foreground && paused) {
foreground = false;
DebugLog.log("went background");
for (Listener l : listeners) {
try {
l.onBecameBackground();
} catch (Exception exc) {
DebugLog.log("Listener threw exception!:" + exc.toString());
}
}
} else {
DebugLog.log("still foreground");
}
}
}, CHECK_DELAY);
}

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}

@Override
public void onActivityStarted(Activity activity) {
}

@Override
public void onActivityStopped(Activity activity) {
}

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

@Override
public void onActivityDestroyed(Activity activity) {
}
}

使用:

在自定义Application#onCreate中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ForegroundCallbacks.init(this);
ForegroundCallbacks.get().addListener(new ForegroundCallbacks.Listener() {
@Override
public void onBecameForeground() {
DebugLog.log("当前程序切换到前台");
}

@Override
public void onBecameBackground() {
DebugLog.log("当前程序切换到后台");
for (Activity activity: AppActivityMgr.INST.getActivities()) {
activity.finish();
}
//添加延迟是为了异常捕获能有时间写好错误文件
new Handler().postDelayed(() -> android.os.Process.killProcess(android.os.Process.myPid()), 500);
}
});