前言


由于一个同学问到我如何按照一个流程走好之后回到首页,我以前看到过4个解决方案,后来发现有做个记录和总结的必要,就写了这篇博文。(之前看小强也写过一篇,这里通过自身的分析完整的总结一下以下6种方案,并加上一个DEMO便于大家了解大体流程)

在android的用户交互中,按钮触发的意图(Intent)跳转会为你重新打开新的一个界面活动(Activity),对于之前的界面根据需求进行摧毁(Finish())或则保留。

如果一个交互流程中,是从A开始,按照A - B - C - D - A这样的顺序进行的话,那么B,C,D这3个活动界面会根据你D中最后的操作来进行保留或是摧毁,例如

(1)注册流程中,在A界面点击注册,通过B,C,D界面完成注册后,B,C,D就随之摧毁,而如果D中注册不成功没跳转会A的话,那么B,C,D就不能摧毁,之前所填的内容也必须保留。

(2)客户端交互中,返回首页按钮,由于在频繁的点击打开过多的界面(如微信查看朋友圈),返回首页就必须一个一个back回去,所有有的客户端为了优化用户体验,便会加入一个按钮返回首页(之前打开的全部关闭)。

以上几个例子都涉及到了   ---   如何安全退出多个ACTIVITY    这个问题。

其实,这个问题的解决方案有好多种,并且各有各的优缺点,下面就罗列出多个方案以及各个方案的优缺点所在,以便用户根据需求选择。

知识结构

首先,通过大致的思维导图罗列出了以下几个知识点,来帮助你去分析学习:

1.Activity的启动模式                        

2.intent:  Flags属性,以及其显、隐式

3.Application : 全局的使用

4.Activity:  onActivityResult(int requestCode, int resultCode, Intent data)方法

5.栈的概念:Last-In/First-Out(LIFO)   ---  后进先出的原则

6.BroadcastReceiver 广播

7.栈的引申的知识点:(1)ArrayList和LinkedList的区别
 (2)android 栈和队列

以上的 (1)Activity的启动模式  (2)intent:  Flags属性  (3)栈的概念         

我通过一篇文章写明了他们3者的联系可以点击以下链接查看

Activity启动模式
及 Intent Flags 与 栈 的关联分析

具体方案


方案1

方法:采用FLAG_ACTIVITY_CLEAR_TOP退出整个程序(多activity)

思路:通过Intent的Flags来控制堆栈去解决

android中,每打开一个Activity,便会在栈中加入一个Activity,当该Activity被摧毁后,栈中便移除了它,并且栈中的Activity是按照开打的先后顺序依次排排列的。

Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在A窗口打开B窗口时在Intent中直接加入标 志 Intent.FLAG_ACTIVITY_CLEAR_TOP,这样开启B时将会清除该进程空间的所有Activity。

代码:

在注册流程最后的FourthStep.class中,点击完成注册点击事件

[java] view
plain
copy

  1. btn_finish.setOnClickListener(new OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. // TODO Auto-generated method stub
  5. Intent intent = new Intent(INTENT_METHOD_FIRST_SINGUP);
  6. intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  7. startActivity(intent);
  8. }
  9. });

其中的 INTENT_METHOD_FIRST_SINGUP 是登录界面的Intent隐式Action。

优缺点:

优:使用对栈的巧妙利用,不会赞成内存无故占用等问题,个人认为这个方法是首选。

方案2

方法:通过堆栈管理器去管理

思路:通过堆栈管理器,对Stack进的存储Activity进行操作(推入,推出,弹出)

代码:

[java] view
plain
copy

  1. public class StackManager {
  2. /**
  3. * Stack 中对应的Activity列表  (也可以写做 Stack<Activity>)
  4. */
  5. private static Stack mActivityStack;
  6. private static StackManager mInstance;
  7. /**
  8. * @描述 获取栈管理工具
  9. * @return ActivityManager
  10. */
  11. public static StackManager getStackManager() {
  12. if (mInstance == null) {
  13. mInstance = new StackManager();
  14. }
  15. return mInstance;
  16. }
  17. /**
  18. * 推出栈顶Activity
  19. */
  20. public void popActivity(Activity activity) {
  21. if (activity != null) {
  22. activity.finish();
  23. mActivityStack.remove(activity);
  24. activity = null;
  25. }
  26. }
  27. /**
  28. * 获得当前栈顶Activity
  29. */
  30. public Activity currentActivity() {
  31. //lastElement()获取最后个子元素,这里是栈顶的Activity
  32. if(mActivityStack == null || mActivityStack.size() ==0){
  33. return null;
  34. }
  35. Activity activity = (Activity) mActivityStack.lastElement();
  36. return activity;
  37. }
  38. /**
  39. * 将当前Activity推入栈中
  40. */
  41. public void pushActivity(Activity activity) {
  42. if (mActivityStack == null) {
  43. mActivityStack = new Stack();
  44. }
  45. mActivityStack.add(activity);
  46. }
  47. /**
  48. * 弹出指定的clsss所在栈顶部的中所有Activity
  49. * @clsss : 指定的类
  50. */
  51. public void popTopActivitys(Class clsss) {
  52. while (true) {
  53. Activity activity = currentActivity();
  54. if (activity == null) {
  55. break;
  56. }
  57. if (activity.getClass().equals(clsss)) {
  58. break;
  59. }
  60. popActivity(activity);
  61. }
  62. }
  63. /**
  64. * 弹出栈中所有Activity
  65. */
  66. public void popAllActivitys() {
  67. while (true) {
  68. Activity activity = currentActivity();
  69. if (activity == null) {
  70. break;
  71. }
  72. popActivity(activity);
  73. }
  74. }
  75. }

之后在注册流程中的对应步骤的Activity的onCreate()中把当前Activity推入栈列表,完成注册流程后,弹出栈列表中流程所涉及的Activity。

优缺点:

缺:如果处理不当,容易造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。

方案3:

方法:全局记录打开的Activity或通过一个自定义的类去管理打开的Activity

思路:通过在Application中用一个列表来记录当前所打开的Activity,根据需求去遍历finish()。

描述:和方案2有点类似。

代码:

[java] view
plain
copy

  1. public class AppApplication extends Application {
  2. private static AppApplication mAppApplication;
  3. /** 当前打开的activity列表 */
  4. public ArrayList<Activity> activityList;
  5. @Override
  6. public void onCreate() {
  7. // TODO Auto-generated method stub
  8. super.onCreate();
  9. mAppApplication = this;
  10. }
  11. /** 获取Application */
  12. public static AppApplication getApp() {
  13. if (mAppApplication == null) {
  14. mAppApplication = new AppApplication();
  15. }
  16. return mAppApplication;
  17. }
  18. /** 添加当前Activity 到列表中 */
  19. public void addActivity(Activity acitivity) {
  20. if(activityList == null){
  21. activityList = new ArrayList<Activity>();
  22. }
  23. activityList.add(acitivity);
  24. }
  25. /** 清空列表,取消引用*/
  26. public void clearActivity(){
  27. activityList.clear();
  28. }
  29. /** 遍历退出所有Activity */
  30. public void exit() {
  31. for (Activity activity : activityList) {
  32. activity.finish();
  33. }
  34. clearActivity();//千万记得清空取消引用。
  35. System.exit(0);
  36. }

使用流程和方法2类似。

优缺点:

缺:如果处理不当,容易造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。

方案4

方法:使用广播机制解决

思路:通过Activity创建的时候,设置监听广播,在注册流程最后步完成注册时候,发送广播进行遍历finish().

描述:这里我把这些广播的初始化都写在了基类BaseActivity里面,便于维护。

代码:

[java] view
plain
copy

  1. /**
  2. * 初始化退出广播
  3. */
  4. public void initFinishReceiver() {
  5. IntentFilter filter = new IntentFilter();
  6. filter.addAction(INIENT_FINISH);
  7. registerReceiver(mFinishReceiver, filter);
  8. }
  9. /**
  10. * 监听是否退出的广播
  11. */
  12. public BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
  13. @Override
  14. public void onReceive(Context context, Intent intent) {
  15. if (INIENT_FINISH.equals(intent.getAction())) {
  16. finish();
  17. }
  18. }
  19. };

在流程中的每步Activity中,初始化广播,之后在点击完成注册时候,发送广播

[java] view
plain
copy

  1. btn_finish.setOnClickListener(new OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. // TODO Auto-generated method stub
  5. getApplicationContext().sendBroadcast(new Intent(INIENT_FINISH));
  6. }
  7. });

优缺点:

缺:开启过多的广播监听,觉得会浪费资源。

方案5:

方法:通过Activity跳转中传递requestCode的之后根据onActivityResult(int
requestCode, int resultCode, Intent data)中返回的resultCode遍历关闭Activity

思路:使用startActivityForResult(intent, requestCode)方法跳转,并且通过

描述:这里我把这些广播的初始化都写在了基类BaseActivity里面便于查看。

代码:

[java] view
plain
copy

  1. /** 关闭时候的requestCode请求码 */
  2. public final static int FINISH_REQUESTCODE = 1;
  3. /** 关闭时候的resultCode请求码 */
  4. public final static int FINISH_RESULTCODE = 1;
  5. /**
  6. * 方法5通过回调关闭的时候用到
  7. */
  8. @Override
  9. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  10. // TODO Auto-generated method stub
  11. if(requestCode == FINISH_REQUESTCODE ){
  12. if(resultCode == FINISH_RESULTCODE){
  13. setResult(FINISH_RESULTCODE);
  14. finish();
  15. }
  16. }
  17. super.onActivityResult(requestCode, resultCode, data);
  18. }

之后在流程的Activity中调用带请求码的Intent跳转意图。

[java] view
plain
copy

  1. startActivityForResult(new Intent(getApplicationContext(), SecondStep.class),FINISH_REQUESTCODE);

在最后完成注册流程的时候通过以下方式返回:

[java] view
plain
copy

  1. btn_finish.setOnClickListener(new OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. // TODO Auto-generated method stub
  5. setResult(FINISH_RESULTCODE);
  6. finish();
  7. }
  8. });

优缺点:

方案6(不推荐)

方法:方法有人说可以使用抛出异常来退出,可是这样会影响到用户体验,所以不推荐

总结

以上便是我从注册流程分析如何安全退出多个ACTIVITY 的汇总总结,综上所述,博主觉得方案1是最可行的方法,如有什么错误之处,望大家提出,马上改正。

源码DEMO


最后附上源码:下载地址

(以上方式中都已经讲到了对应的方法和代码,源码可以更好的帮助你去体验下这几种方式的使用流程)

安全退出app,activoty栈管理的更多相关文章

  1. Android解析ActivityManagerService(二)ActivityTask和Activity栈管理

    前言 关于AMS,原计划是只写一篇文章来介绍,但是AMS功能繁多,一篇文章的篇幅远远不够.这一篇我们接着来学习与AMS相关的ActivityTask和Activity栈管理. 1.ActivitySt ...

  2. Android实现点击两次返回退出APP

    Android实现点击两次退出APP 这两天在做一个项目碰到这么个问题,需要主界面点击两次直接退出整个APP而不是返回上一个界面,查找了网上的资料,整合和修改了一下写了这篇博客. 这里我主要以我的项目 ...

  3. Activity 生命周期及其栈管理方式

    Activity 生命周期 Android 系统用栈的形式管理 Activity , 当新的 Activity 被创建是, 会被放置到栈顶, 这个 Activity 会进入到运行状态, 而前一个 Ac ...

  4. ActivityJump+ActivityManager【Activity之间的跳转和Activity任务栈管理】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 封装Activity跳转的方法以及实现Activity任务栈管理. 效果图   代码分析 ActivityJump:封装Activi ...

  5. 对于一键退出APP功能实现的技术探讨

    在Android的开发过程中,会经常存在“一键退出APP”的需求.经过一段时间的整理,其主要实现方式有以下几种. 本质:一键结束当前APP的所有activity&一键结束当前APP进程,两者合 ...

  6. iOS 之 退出app(项目)的几种方法

    路漫漫其修远兮,吾将上下而求索.也算是对程序员的一种真实写照了吧. 今天想研究一下iOS中退出项目的方法,说是今天,其实也关注并去了解很久了.只是始终找不到自己认为很好的方法.今天就先把自己了解的列举 ...

  7. Android开发之点击两次Back键退出App

    Back按键的方法是onKeyDown()方法,重写该方法就可以改变back按键的作用. 实现点击两次Back按键退出app,有两种方法: 方法1. private static boolean is ...

  8. Android:后台给button绑定onClick事件、当返回项目到手机页面时提示是否退出APP

    上一篇文章我们学习了android通过findViewById的方式查找控件,本章将了解button控件,及btton如何绑定控件. 通过android的ui设计工具设计一个登录页面: <Rel ...

  9. Android Studio设置连续按两次退出APP

    主要是在onKeyDown方法中进行操作,直接上代码. private long mTime; @Override public boolean onKeyDown(int keyCode, KeyE ...

随机推荐

  1. iOS开源加密相册Agony的实现(三)

    简介 虽然目前市面上有一些不错的加密相册App,但不是内置广告,就是对上传的张数有所限制.本文介绍了一个加密相册的制作过程,该加密相册将包括多密码(输入不同的密码即可访问不同的空间,可掩人耳目).Wi ...

  2. ROS探索总结(十八)——重读tf

    在之前的博客中,有讲解tf的相关内容,本篇博客重新整理了tf的介绍和学习内容,对tf的认识会更加系统. 1 tf简介 1.1 什么是tf tf是一个让用户随时间跟踪多个参考系的功能包,它使用一种树型数 ...

  3. 一个整数数组,有n个整数,如何找其中m个数的和等于另外n-m个数的和?

    int getSum(int* arr, int len) { int sum = 0; for (int i = 0; i < len; ++i) { sum += arr[i]; } ret ...

  4. SpriteKit:检测当新场景显示以后

    Detecting When a New Scene Is Presented Sprite Kit在SKScene类中提供2个可以重载的方法用来检测当一个场景过渡出去或过渡进来的时候. 第一个方法是 ...

  5. [django1.6]跑批任务错误(2006, 'MySQL server has gone away')

    有个django的定时任务的需求,调用django的orm来对数据库进行数据处理.  在交互环境下直接启动pyhton脚本没有问题,放在定时任务中时候,总是出现 (2006, 'MySQL serve ...

  6. UNIX网络编程——原始套接字(dos攻击)

    原始套接字(SOCK_RAW).应用原始套接字,我们可以编写出由TCP和UDP套接字不能够实现的功能. 注意原始套接字只能够由有 root权限的人创建. 可以参考前面的博客<<UNIX网络 ...

  7. 自动滚动的TextView

    自动滚动的TextView 效果图 XML文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/andr ...

  8. layout文件夹中activity_main.xml与fragment_main.xml文件的处理记录

    androidSDK更新到22.6后新建立项目时在layout文件夹下面出现了activity_main.xml与fragment_main.xml,这是为了在平板开发中使用碎片,但是让不需要碎片的人 ...

  9. 1.搜索引擎的历史,搜索引擎起步,发展,繁荣,搜索引擎的原理,搜索技术用途,信息检索过程,倒排索引,什么是Lucene,Lucene快速入门

     一: 1  搜索引擎的历史 萌芽:Archie.Gopher Archie:搜索FTP服务器上的文件 Gopher:索引网页 2  起步:Robot(网络机器人)的出现与spider(网络爬虫) ...

  10. 混合开发(一)——WebView开发高级技巧之加载网页以及JavaScript,加载进度条

    混合开发(一)--WebView开发高级技巧之加载网页以及JavaScript,加载进度条 现在关于混合开发也越来越多了,很多人喜欢跟随,比如HB,比如RN,其实这东西很早就有这么一个概念了,而且说实 ...