美文网首页面试Android 日记Android资源收录
Android-完全退出当前应用程序-新公司学习到的细节

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

作者: 影响身边的人 | 来源:发表于2016-08-18 19:24 被阅读3997次

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

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

    比如,今天就实践一个退出很多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);
        }
    

    相关文章

      网友评论

      • 721d739b6619:你说的第三个方法有误区吧。如果我是 A->B->C->D;ABCD代表Activity。现在我当前的Activity是D,前面有ABC三个Activity,现在我从D跳去B;用FLAG_ACTIVITY_CLEAR_TOP时,栈中的Activity还有A,B吧,且B是当前的Activity。所以你用FLAG_ACTIVITY_CLEAR_TOP标记是不会将栈的所有Activity清除的。如果你说每个Activity跳转都用FLAG_ACTIVITY_CLEAR_TOP;那么不如直接将启动模式设为:SingleTask;但这样你说的那种登录模式的情况就不可能出现了(即A->B->C->D)
      • Mr_Quan:Intent.FLAG_ACTIVITY_CLEAR_TOP:smile:
      • d9b37f45f8e3:类似于广播,用EventBus发消息,接收到后finish,我是这么做的
        Mr_Quan:EventBus这把双刃剑,为啥不直接用广播?
      • 十月1024:不明觉厉!😃
        影响身边的人:@等待我的she 😊

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

      本文链接:https://www.haomeiwen.com/subject/chnvsttx.html