几种退出 Activity 的方式
今天学习 Activity 的 4 种 launch mode,学到 SingleTask 模式的时候,想起在微博上曾经转发过一篇利用 SingleTask 来优雅地退出 App 的文章,于是把这篇拿来复习一下,顺便加点自己的理解。话说我转了这么多的微博,什么时候才能看完...
容器式
其核心思想是:使用一个容器类管存储 Activity 的引用,在需要的时候遍历容器,执行 Activity 的 finish()
方法即可退出 App。实现如下:
容器类
import android.app.Activity;
import java.util.ArrayList;
import java.util.List;
/**
* Activity 容器,存储 Activity 的引用
*
* Created by Owen on 2016/5/9.
*/
public class ActivityContainer {
private static List<Activity> sActivities = new ArrayList<>();
private ActivityContainer() {}
public static void addActivity(Activity activity) {
sActivities.add(activity);
}
public static void removeActivity(Activity activity) {
sActivities.remove(activity);
}
public void finishAllActivity() {
for (int i = 0; i < sActivities.size(); i++) {
if (sActivities.get(i) != null && !sActivities.get(i).isFinishing()) {
sActivities.get(i).finish();
}
}
sActivities.clear();
}
}
在 BaseActivity
中添加相应方法
import android.app.Activity;
import android.os.Bundle;
/**
* 项目中所有的 Activity 都继承该类,方便统一管理
*
* Created by Owen on 2016/5/9.
*/
public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityContainer.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityContainer.removeActivity(this);
}
}
曾经看同事使用这种方法来管理 Activity,感觉还挺好用。但是,这种方法有一个缺陷,因为 ActivityContainer
存储的是 Activity 的强引用,如果不注意的话,容易造成内存泄漏。所以,还是不推荐用这个办法。
既然用强引用不行,那么用软引用(WeakReference)行不行?不行吧,我们的目的是要退出整个 App,而软引用因为其特点,无法实现我们的目的。所以,不行,不行,真的不行。
广播式
自定义一个 Activity —— BaseActivity
,由它来监听退出 App 的广播。
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
/**
* 项目中所有的 Activity 都继承该类,方便统一管理
*
* Created by Owen on 2016/5/9.
*/
public class BaseActivity extends Activity {
public static final String ACTION_EXIT = "action_exit";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_EXIT);
registerReceiver(exitReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(exitReceiver);
}
private BroadcastReceiver exitReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_EXIT.equals(intent.getAction())) {
finish();
}
}
};
}
并为它添加一个方法:exitApp
,用来退出 App
protected void exitApp() {
Intent intent = new Intent(ACTION_EXIT);
sendBroadcast(intent);
}
在适当的地方调用这个方法来发送广播。一旦 BaseActivity
接收到了响应的广播,就会执行 finish()
方法,于是应用就退出了。
哎呦,这种方法不错哦。有没有更好的?
Broadcast Receiver + singleTask
singleTask 作为 Android 的 launchMode,有一个特点:
启动 Activity 时,会在当前的栈中查找有没有存在这个 Activity 的实例。如果存在,就将它置于栈顶,并将其之上的其他 Activity 移出栈外。
另外,我们的 App 都有一个 MainActivity 作为主页。不管我们怎么进行 Activity 之间的跳转,最终我们都要回到主页。
基于这两点,只需要两步就可以实现优雅地退出 App 了
- 只为 MainActivity 注册退出广播,接收到广播就执行
finish()
方法 - 将 MainActivity 的 launchMode 设置为
singleTask
实现如下:
监听广播
/**
* App 主页
*
* Created by Owen on 2016/5/9.
*/
public class MainActivity extends Activity {
public static final String ACTION_EXIT = "action_exit";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_EXIT);
registerReceiver(exitReceiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(exitReceiver);
}
private BroadcastReceiver exitReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_EXIT.equals(intent.getAction())) {
finish();
}
}
};
}
在 AndroidManifest.xml 设置 launchMode
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
在适当的地方调用如下代码
Intent startMainIntent = new Intent(this, MainActivity.class);
startActivity(startMainIntent);
Intent intent = new Intent(BaseActivity.ACTION_EXIT);
sendBroadcast(intent);
就这样,优雅地实现了 App 的退出。
额,不行,不满意,能不能再更屌一点?当然可以
SingleTask
根据微博上网友的评论,就有了这个办法。连广播都可以不用写了,仅仅使用 SingleTask 的特性就可以。因为将 Activity 的 launchMode 设置为 singleTask 之后,会执行 onNewIntent(Intent intent)
方法。所以,我只需要传入一个标志位就行了,判断标志位来决定要不要退出 App。来看看代码实现:
老样子,设置 launchMode
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
重写 onNewIntent()
方法
/**
* App 主页
*
* Created by Owen on 2016/5/9.
*/
public class MainActivity extends BaseActivity {
public static final String EXTRA_EXIT = "extra_exit";
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
boolean shouldExit = intent.getBooleanExtra(EXTRA_EXIT, false);
if (shouldExit) {
finish();
}
}
}
在适当的地方调用如下方法
Intent startMainIntent = new Intent(this, MainActivity.class);
startMainIntent.putExtra(MainActivity.EXTRA_EXIT, true);
startActivity(startMainIntent);
OK,就这么简单。
讲个题外话
做 App 帐号注册流程的时候,页面的跳转是这样的:欢迎页 -> 手机号和验证码页 -> .... -> 公司信息页-> 再回到欢迎页。总之最后都要回到欢迎页,所以我需要把之前浏览过的页面全部关掉
当时我比较笨,用的是一个容器类把这些 Activity 存储起来,然后再去遍历这些 Activity,执行它们的 finish()
方法。后来被嘲笑了。
其实,我可以设置一下 IntentFlag 为 FLAG_ACTIVITY_CLEAR_TOP
。FLAG_ACTIVITY_CLEAR_TOP
就相当于 singleTask。
Intent intent = new Intent(this, WelcomeActivity.class);
intent .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
这些页面 :手机号和验证码页 -> .... -> 公司信息页,对与欢迎页来说,在栈内部,都处于欢迎页之上,所以利用这个 IntentFlag 可以清空栈顶,把欢迎页置顶。这样就能把之前所有的 Activity 都关掉了。这样不是很简单吗?
总结
- singleTask 的特点
- 写代码多优化
参考来源
- 来源微博 : Android退出应用最优雅的方式 - 安卓开发频道
- 来源微博:程序猴 http://www.jianshu.com/p/e6112acbd2f4