Android-完全退出当前应用程序-新公司学习到的细节

上家公司因为某些原因离职了,于是每天出去面试也没时间来写我的博客了,这两天结束了十来天的动荡,算是稳定下来了,又重新拾起纸笔,写上两笔。

看公司代码的时候就在想,一个维护了两年的项目势必是有他独特的地方的,于是乎,在很多小细节的地方,以前虽然也面试准备过,可是确实没写过。这些东西,可能看起来不起眼,平时没什么用,可能在某些时候避免了程序崩溃的危险呢。

比如,今天就实践一个退出很多Activity的功能,在某些情况下保证安全。


借鉴一篇博客中的例子吧:(注册流程)

如果一个交互流程中,是从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. Dalvik VM的本地方法

android.os.Process.killProcess(android.os.Process.myPid()) //获取PID
System.exit(0); //常规java、c#的标准退出法,返回值为0代表正常退出

2. 任务管理器方法

首先要说明该方法运行在Android 1.5 API Level为3以上才可以,同时需要权限

  ActivityManager am = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);
  am.restartPackage(getPackageName()); 

系统会将,该包下的 ,所有进程,服务,全部杀掉,就可以杀干净了,要注意加上

 <uses-permission android:name=\"android.permission.RESTART_PACKAGES\"></uses-permission>

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

思路:通过Intent的Flags来控制堆栈去解决
android中,每打开一个Activity,便会在栈中加入一个Activity,当该Activity被摧毁后,栈中便移除了它,并且栈中的Activity是按照开打的先后顺序依次排排列的。
Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在A窗口打开B窗口时在Intent中直接加入标 志 Intent.FLAG_ACTIVITY_CLEAR_TOP,这样开启B时将会清除该进程空间的所有Activity。

btn_finish.setOnClickListener(new OnClickListener() {  
  
    @Override  
    public void onClick(View v) {  
        // TODO Auto-generated method stub  
        Intent intent = new Intent(INTENT_METHOD_FIRST_SINGUP);  
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
        startActivity(intent);  
    }  
});  

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

优缺点:
优:使用对栈的巧妙利用,不会造成内存无故占用等问题


4.自定义一个Actiivty 栈,道理同上,不过利用一个单例模式的Activity栈来管理所有Activity。并提供退出所有Activity的方法。代码如下:

   public class ScreenManager {
 private static Stack<Activity> activityStack;
 private static ScreenManager instance;
 private  ScreenManager(){
 }
 public static ScreenManager getScreenManager(){
  if(instance==null){
   instance=new ScreenManager();
  }
  return instance;
 }
//退出栈顶Activity
 public void popActivity(Activity activity){
  if(activity!=null){
   activity.finish();
   activityStack.remove(activity);
   activity=null;
  }
 }

//获得当前栈顶Activity
 public Activity currentActivity(){
  Activity activity=activityStack.lastElement();
  return activity;
 }

//将当前Activity推入栈中
 public void pushActivity(Activity activity){
  if(activityStack==null){
   activityStack=new Stack<Activity>();
  }
  activityStack.add(activity);
 }
 //退出栈中所有Activity
 public void popAllActivityExceptOne(Class cls){
  while(true){
   Activity activity=currentActivity();
   if(activity==null){
    break;
   }
   if(activity.getClass().equals(cls) ){
    break;
   }
   popActivity(activity);
  }
 }
}

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

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

public class AppApplication extends Application {  
    private static AppApplication mAppApplication;  
    /** 当前打开的activity列表 */  
    public ArrayList<Activity> activityList;  
  
    @Override  
    public void onCreate() {  
        // TODO Auto-generated method stub  
        super.onCreate();  
        mAppApplication = this;  
    }  
  
    /** 获取Application */  
    public static AppApplication getApp() {  
        if (mAppApplication == null) {  
            mAppApplication = new AppApplication();  
        }  
        return mAppApplication;  
    }  
  
    /** 添加当前Activity 到列表中 */  
    public void addActivity(Activity acitivity) {  
        if(activityList == null){  
            activityList = new ArrayList<Activity>();  
        }  
        activityList.add(acitivity);  
    }  
      
    /** 清空列表,取消引用*/  
    public void clearActivity(){  
        activityList.clear();  
    }  
  
    /** 遍历退出所有Activity */  
    public void exit() {  
        for (Activity activity : activityList) {  
            activity.finish();  
        }  
        clearActivity();//千万记得清空取消引用。  
        System.exit(0);  
    }  

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


6.使用广播机制解决

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

代码:

/** 
 * 初始化退出广播 
 */  
public void initFinishReceiver() {  
    IntentFilter filter = new IntentFilter();  
    filter.addAction(INIENT_FINISH);  
    registerReceiver(mFinishReceiver, filter);  
}  
  
/** 
 * 监听是否退出的广播 
 */  
public BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {  
  
    @Override  
    public void onReceive(Context context, Intent intent) {  
        if (INIENT_FINISH.equals(intent.getAction())) {  
            finish();  
        }  
    }  
};  
在流程中的每步Activity中,初始化广播,之后在点击完成注册时候,发送广播
[java] view plain copy 在CODE上查看代码片派生到我的代码片
btn_finish.setOnClickListener(new OnClickListener() {  
  
    @Override  
    public void onClick(View v) {  
        // TODO Auto-generated method stub  
        getApplicationContext().sendBroadcast(new Intent(INIENT_FINISH));  
    }  
});  

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

我这边采用第三种方法,如下

public void exit() {
        Intent intent = new Intent();
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.setClass(this, HomePageActivity.class);
        intent.putExtra("exitApp", true);
        
        Misc.startActivity(intent);
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容