Android中一个Activity关闭另一个Activity或者在一个Activity中关闭多个Activity

待兔 等级 468 1 1

前言

最近项目中涉及需要在一个Activity中关闭另一个Activity或者在一个Activity中关闭多个Activity的需求,不涉及到应用的退出。自己首先想了一些方案,同时也查了一些方案,就各个方案比较下优劣。


方案一

广播的方式

这个是最容易想到的,同时也是网上提供最多的。
由于多个Activity要使用,关闭页面的广播最好写在基类BaseActivity中,也可以在各个子页面单独写,但是代码量就增加了。

public class BaseActivity extends Activity {

    //根据需求定义自己需要关闭页面的action
    public static final String RECEIVER_ACTION_FINISH_A = "receiver_action_finish_a";
    public static final String RECEIVER_ACTION_FINISH_B = "receiver_action_finish_b";
    public static final String RECEIVER_ACTION_FINISH_C = "receiver_action_finish_c";
    public static final String RECEIVER_ACTION_FINISH_D = "receiver_action_finish_d";

    private FinishActivityRecevier mRecevier;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mRecevier = new FinishActivityRecevier();
        registerFinishReciver();
    }

    private void registerFinishReciver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(RECEIVER_ACTION_FINISH_A);
        intentFilter.addAction(RECEIVER_ACTION_FINISH_B);
        intentFilter.addAction(RECEIVER_ACTION_FINISH_C);
        intentFilter.addAction(RECEIVER_ACTION_FINISH_D);
        registerReceiver(mRecevier, intentFilter);
    }

    private class FinishActivityRecevier extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //根据需求添加自己需要关闭页面的action
            if (RECEIVER_ACTION_FINISH_A.equals(intent.getAction()) ||
                    RECEIVER_ACTION_FINISH_B.equals(intent.getAction()) ||
                    RECEIVER_ACTION_FINISH_C.equals(intent.getAction()) ||
                    RECEIVER_ACTION_FINISH_D.equals(intent.getAction())) {
                BaseActivity.this.finish();
            }
        }
    }

    @Override
    protected void onDestroy() {
        if (mRecevier != null) {
            unregisterReceiver(mRecevier);
        }
        super.onDestroy();
    }
} 

发送广播就需要在各个需求子Activity中进行了,这里使用工具类,方便以后多次或者拓展使用,只需要在需求子Activity中直接调用就行。

public class BroadcastUtils {
    /**
     * 发送finish页面的广播
     * action可以自己根据需要添加
     * @param context
     */
    public static void sendFinishActivityBroadcast(Context context) {
        Intent intent = new Intent(BaseActivity.RECEIVER_ACTION_FINISH_B);
        context.sendBroadcast(intent);
        intent = new Intent(BaseActivity.RECEIVER_ACTION_FINISH_C);
        context.sendBroadcast(intent);
    }
} 

优劣:
有点:最常规使用,不会出现内存泄漏,在基类中操作,代码量不多。
缺点:项目中若是需要关闭页面多的话,需要发送大量广播,会降低性能。

方案二

直接static activity方式

这是网上提供的,代码一看就明显的内存泄漏。但是。。。。。。

 private static AActivity sInstance;
    public static AActivity getInstance() {
        if (sInstance != null) {
            return sInstance;
        }
        return null;
    }
    public static void finishActivity() {
        if (sInstance != null) {
            sInstance.finish();
        }
    } 

内存泄漏明显,之所以有但是,那是因为这种方式让我想到加入弱引用WeakReference的方式。

public class BActivity extends BaseActivity {
    private static WeakReference<BActivity> sActivityRef;

    public static void finishActivity() {
        if (sActivityRef != null && sActivityRef.get() != null) {
            sActivityRef.get().finish();
        }
    }
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);
        sActivityRef = new WeakReference<>(this);
        Button btnB = (Button) findViewById(R.id.btn_b);
        btnB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(BActivity.this, CActivity.class));
            }
        });
    }

} 

纠结点在于,WeakReference被static之后,里面包裹的引用会被影响吗?查了一下WeakReference以及JVM相关,虽然WeakReference被static了,生命周期变长了,但是WeakReference关联的对象不受影响的,依然遵循WeakReference在gc时候的规则。

优劣:
优点:代码简单直观,引入WeakReference,解决了内存泄漏问题。
缺点:在每个activity中都要添加,代码量多。(不知是否可抽取到积累中,以后尝试)

方案三

使用集合或者栈的方式

这种方式网上很多,但是。。。。。。

public class FinishActivityManager extends BaseActivity {
    private FinishActivityManager() {
    }
    private static FinishActivityManager sManager;
    private List<Activity> activityList;
    public static FinishActivityManager getManager() {
        if (sManager == null) {
            synchronized (FinishActivityManager.class) {
                if (sManager == null) {
                    sManager = new FinishActivityManager();
                }
            }
        }
        return sManager;
    }
    /**
     * 添加Activity到集合中
     */
    public void addActivity(Activity activity) {
        if (activityList == null) {
            activityList = new LinkedList<>();
        }
        activityList.add(activity);
    }
    /**
     * 关闭指定的Activity
     */
    public void finishActivity(Activity activity) {
        if (activityList != null && activity != null && activityList.contains(activity)) {
            //使用迭代器安全删除
            for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) {
                Activity temp = it.next();
                // 清理掉已经释放的activity
                if (temp == null) {
                    it.remove();
                    continue;
                }
                if (temp == activity) {
                    it.remove();
                }
            }
            activity.finish();
        }
    }
    /**
     * 关闭指定类名的Activity
     */
    public void finishActivity(Class<?> cls) {
        if (activityList != null) {
            // 使用迭代器安全删除
            for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) {
                Activity activity = it.next();
                // 清理掉已经释放的activity
                if (activity == null) {
                    it.remove();
                    continue;
                }
                if (activity.getClass().equals(cls)) {
                    it.remove();
                    activity.finish();
                }
            }
        }
    }
    /**
     * 关闭所有的Activity
     */
    public void finishAllActivity() {
        if (activityList != null) {
            for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) {
                Activity activity = it.next();
                if (activity != null) {
                    activity.finish();
                }
            }
            activityList.clear();
        }
    }
    /**
     * 退出应用程序
     */
    public void exitApp() {
        try {
            finishAllActivity();
            // 退出JVM,释放所占内存资源,0表示正常退出
            System.exit(0);
            // 从系统中kill掉应用程序
                android.os.Process.killProcess(android.os.Process.myPid());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
} 

又有但是,这种方式注意在删除的时候使用迭代器,否则会出现并发修改异常。
那就来说说但是,应用中要是不使用这种封装的方式去finish掉Activity的时候,封装的manager并不知道,没有断开并释放掉其引用,会引起内存泄漏。所以WeakReference又要出场了,继续修改吧。

public class FinishActivityManager extends BaseActivity {
    private FinishActivityManager() {
    }
    private static FinishActivityManager sManager;
    private Stack<WeakReference<Activity>> mActivityStack;
    public static FinishActivityManager getManager() {
        if (sManager == null) {
            synchronized (FinishActivityManager.class) {
                if (sManager == null) {
                    sManager = new FinishActivityManager();
                }
            }
        }
        return sManager;
    }
    /**
     * 添加Activity到栈
     * @param activity
     */
    public void addActivity(Activity activity) {
        if (mActivityStack == null) {
            mActivityStack = new Stack<>();
        }
        mActivityStack.add(new WeakReference<>(activity));
    }

    /**
     * 检查弱引用是否释放,若释放,则从栈中清理掉该元素
     */
    public void checkWeakReference() {
        if (mActivityStack != null) {
            // 使用迭代器进行安全删除
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity temp = activityReference.get();
                if (temp == null) {
                    it.remove();
                }
            }
        }
    }
    /**
     * 获取当前Activity(栈中最后一个压入的)
     * @return
     */
    public Activity currentActivity() {
        checkWeakReference();
        if (mActivityStack != null && !mActivityStack.isEmpty()) {
            return mActivityStack.lastElement().get();
        }
        return null;
    }
    /**
     * 关闭当前Activity(栈中最后一个压入的)
     */
    public void finishActivity() {
        Activity activity = currentActivity();
        if (activity != null) {
            finishActivity(activity);
        }
    }
    /**
     * 关闭指定的Activity
     * @param activity
     */
    public void finishActivity(Activity activity) {
        if (activity != null && mActivityStack != null) {
            // 使用迭代器进行安全删除
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity temp = activityReference.get();
                // 清理掉已经释放的activity
                if (temp == null) {
                    it.remove();
                    continue;
                }
                if (temp == activity) {
                    it.remove();
                }
            }
            activity.finish();
        }
    }
    /**
     * 关闭指定类名的所有Activity
     * @param cls
     */
    public void finishActivity(Class<?> cls) {
        if (mActivityStack != null) {
            // 使用迭代器进行安全删除
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity activity = activityReference.get();
                // 清理掉已经释放的activity
                if (activity == null) {
                    it.remove();
                    continue;
                }
                if (activity.getClass().equals(cls)) {
                    it.remove();
                    activity.finish();
                }
            }
        }
    }
    /**
     * 结束所有Activity
     */
    public void finishAllActivity() {
        if (mActivityStack != null) {
            for (WeakReference<Activity> activityReference : mActivityStack) {
                Activity activity = activityReference.get();
                if (activity != null) {
                    activity.finish();
                }
            }
            mActivityStack.clear();
        }
    }
    /**
     * 退出应用程序
     */
    public void exitApp() {
        try {
            finishAllActivity();
            // 退出JVM,释放所占内存资源,0表示正常退出
            System.exit(0);
            // 从系统中kill掉应用程序
            android.os.Process.killProcess(android.os.Process.myPid());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
} 

代码一目了然,之所以改成Stack,是因为要模仿Activity的任务栈的方式,关闭最后打开的Activity更加方便。
使用的话,在BaseActivity中onCreate()中addActivity,在onDestroy()中finishActivity(),其他功能在各个子Activity中根据需要添加。

优劣:
优点:一劳永逸,一次封装,方便后续使用。
缺点:暂无。

方案四

使用Activity的launchMode

根据Android启动模式,standard和singleTop并不能实现项目需求,故排除。

singleTask和singleInstance在使用的时候会和onActivityResult()有点关系:
Android 5.0以上的版本能正常使用,没有冲突;
Android 5.0以下的版本有个bug,在调用了startActivityForResult之后立马就会调用onActivityResult,不会等到打开的Activity返回的时候才调用。
项目中很多Activity种都有startActivityForResult,故此种方式排除掉。

方案五

使用onActivityResult方式

根据方案四,此方式需要配合launchMode的standard和singleTop使用才能达到效果,所以局限性很大。

总结

以上就是几种方案的对比,要是项目中需要关闭Activity不多,不需要发送大量广播,可以使用方案一;方案二和方案三有异曲同工之处,首先推荐方案三。

能力有限,有不对之处,欢迎指出。

收藏
评论区

相关推荐

Android Activity生命周期,启动模式,启动过程详解
前言 接触过Android开发的同学都知道Activity,Activity作为Android四大组件之一,使用频率高。简单来说Activity提供了一个显示界面,让用户进行各种操作,本文主要分为以下三个部分:Activity的生命周期,启动模式,以及Activity的工作过程。文中大部分篇幅来自《Android开发艺术探索》一书,尽管想多以流程或图
Android中一个Activity关闭另一个Activity或者在一个Activity中关闭多个Activity
前言 最近项目中涉及需要在一个Activity中关闭另一个Activity或者在一个Activity中关闭多个Activity的需求,不涉及到应用的退出。自己首先想了一些方案,同时也查了一些方案,就各个方案比较下优劣。 方案一 广播的方式 这个是最容易想到的,同时也是网上提供最多的。 由于多个Activity要使用,关闭页面
Android通过URL打开Activity
关注公众号 QXF069 为每个 Activity 绑定一个 url 可以方便的让第三方 app 直接打开这些 Activity。也可以方便在 app 内部进行页面跳转,解耦。 背景 举一个常见的案例,假设我们有个产品 A,产品 A 包含 h5 网页端和客户端,当用户在手机打开我们的 h5 网页端的时候,我们会期望如果用户手机安装了我们的客户端,则直接打
重新认识Activity—Activity的生命周期
Activity的生命周期概念 当用户浏览,退出和返回应用时,Activity实例会在其生命周期中转换为不同的状态。在生命周期回调方法中,可以声明用户离开并重新进入Activity时Activity的行为方式。每个回调允许执行适合于给定状态更改的特定工作。生命周期回调的良好实现可以帮助确保您的应用程序避免: 如果用户在使用您的App时接到电话或切换
Android Fragment生命周期
Fragment 是在 Android 3.0 中引入,用于解决不同屏幕分辨率的设备上 UI 显示、交互的问题。Fragment 有自己的布局,有自己的生命周期,有自己的事件响应。 但 Fragment 又是依赖于 Activity 存在的,你可以把多个 Fragment 嵌入到一个 Activity 中或者多个 Activity 重用一个 Fragmen
【Flutter实战】 路由管理
2.2 路由管理路由(Route)在移动开发中通常指页面(Page),这跟web开发中单页应用的Route概念意义是相同的,Route在Android中通常指一个Activity,在iOS中指一个ViewController。所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。Flutter中的路由管理和原生开发类似,无论是Android还是
基于Xposed自动化框架XposedAppium
基于Xposed做的一款自动化点击,滑动框架(基于安卓原生的事件分发)。可以模拟手指的一切操作,基于Xpath表达式获取View。此框架在virjar大佬的框架基础上进行的修改的,修复了部分Bug,添加常用方法等.在登入页面输入账号密码后,跳转到第二个Activity并点击对话框确定按钮。 Xposed模块:很简单,添加对应的Activity,需要实Page
创建圆角Dialog风格的Activity
一、前言:在开发中有时我们需要用到dialog,可是系统提供的dialog有时不能满足我们的要求,比如显示位置等,不够灵活,我们这时可以创建activity,使其风格和dialog一样。二、实现 1\. 1.创建样式在res/values/styles.xml中<style name"DialogActivityStyle"
Android深入理解Context(二)Activity和Service的Context创建过程
Android框架层 Android深入理解Contextcategories: Android框架层本文首发于微信公众号「刘望舒」 前言上一篇文章我们学习了Context关联类和Application Context的创建过程,这一篇我们接着来学习Activity和Service的Context创建过程。需要注意的是,本篇的知识点会和深入理解四大组件系列的
Android深入四大组件(一)应用程序启动过程(前篇)
Android框架层 Android深入四大组件categories: Android框架层本文首发于微信公众号「后厂技术官」 前言在此前的文章中,我讲过了Android系统启动流程和Android应用进程启动过程,这一篇顺理成章来学习Android 7.0的应用程序的启动过程。分析应用程序的启动过程其实就是分析根Activity的启动过程。<!more 1
Android深入四大组件(一)应用程序启动过程(后篇)
Android框架层 Android深入四大组件categories: Android框架层本文首发于微信公众号「刘望舒」 1.ActivityManageService到ApplicationThread的调用流程AMS的startActivity方法中return了startActivityAsUser方法:<!moreframeworks/base/s
Android深入四大组件(七)Android8.0 根Activity启动过程(后篇)
Android框架层 Android深入四大组件categories: Android框架层本文首发于微信公众号「刘望舒」 前言在几个月前我写了和这两篇文章,它们都是基于Android 7.0,当我开始阅读Android 8.0源码时发现应用程序(根Activity)启动过程照Android 7.0有了一些变化,因此又写下了本篇文章,本篇文章照此前的文章不仅
Android解析ActivityManagerService(二)ActivityTask和Activity栈管理
Android框架层 Android系统服务 ActivityManagerService Android框架层本文首发于微信公众号「刘望舒」 前言关于AMS,原计划是只写一篇文章来介绍,但是AMS功能繁多,一篇文章的篇幅远远不够。这一篇我们接着来学习与AMS相关的ActivityTask和Activity栈管理。 1.ActivityStackActivi
Android包管理机制(五)APK是如何被解析的
Android框架层 Android包管理机制 Android框架层本文首发于微信公众号「刘望舒」 前言在本系列的前面文章中,我介绍了PackageInstaller的初始化和安装APK过程、PMS处理APK的安装和PMS的创建过程,这些文章中经常会涉及到一个类,那就是PackageParser,它用来在APK的安装过程中解析APK,那么APK是如何被解析的
IntentFilter匹配规则
1、Activity启动方式我们知道,启动Activity分为两种,显式调用和隐式调用。显式调用需要明确指定被启动对象的组件信息,包括包名和类名。隐式调用不需要指定组件信息,但需要匹配目标组件的IntentFilter中所设置的过滤信息。 2、IntentFilterIntentFilter中的过滤信息包括:action、category、data。为了匹配