几种退出 Activity 的方式

几种退出 Activity 的方式

字数1503  阅读428  评论5 

今天学习 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 了

  1. 只为 MainActivity 注册退出广播,接收到广播就执行 finish() 方法
  2. 将 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_TOPFLAG_ACTIVITY_CLEAR_TOP 就相当于 singleTask。

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

这些页面 :手机号和验证码页 -> .... -> 公司信息页,对与欢迎页来说,在栈内部,都处于欢迎页之上,所以利用这个 IntentFlag 可以清空栈顶,把欢迎页置顶。这样就能把之前所有的 Activity 都关掉了。这样不是很简单吗?

总结


  • singleTask 的特点
  • 写代码多优化

参考来源


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值