阅读 1669

Android 中几种优雅的退出APP方式介绍

前言

最近由于项目的修改,项目由MainActivity按返回键一次退出修改为MainActivity中连续按两次返回键退出,顺便优化一下推出这里的代码。因此还是在网上搜索了一番,总结比较之后得出了有以下集中方式,优缺点都会提出来,有需要的老铁按需选择。

目录

常见的有5中方式:

  • 容器式
  • 便捷式
  • 广播式
  • SingleTask式
  • 进程式

实现方法

1.容器式

容器式可能是我们最常见的方式之一了,主要通过创建一个全局的容器,把所有的Activity都保存下来,退出的时候循环遍历所有activity,然后finish()掉。

BaseActivity添加代码:

public abstract class BaseActivity extends AppCompatActivity{
 @Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     // 添加Activity到堆栈
     ActivityUtils.getInstance().addActivity(this);
 }

 @Override
 protected void onDestroy() {
     super.onDestroy();
     // 结束Activity&从栈中移除该Activity
     ActivityUtils.getInstance().removeActivity(this);
 }

}
复制代码

创建一个全局工具类:

public class ActivityUtils{

   private ActivityUtils() {
   }

   private static AtyContainer instance = new AtyContainer();
   private static List<Activity> activitys = new ArrayList<Activity>();

   public static ActivityUtils getInstance() {
       return instance;
   }

   public void addActivity(Activity activity) {
       activityStack.add(activity);
   }

   public void removeActivity(Activity activity) {
       activityStack.remove(activity);
   }

   /**
    * 结束所有Activity
    */
   public void finishAllActivity() {
       for (int i = 0, size = activityStack.size(); i < size; i++) {
           if (null != activityStack.get(i)) {
               activityStack.get(i).finish();
           }
       }
       activityStack.clear();
   }

}
复制代码

这种方式是有一定的缺点的,我们的工具类ActivityUtils持有Activity的引用,当我们的应用发生异常,ActivityUtils持有的引用没有被销毁会导致部分内存问题,而且代码量多,不够优雅,诸多不便。

但是容器式这种方式还是有解决办法的,我们可以采用弱引用的方式,就不存在前面所说的问题了,习惯于容器式的可以采用弱引用这种方式的。

2.便捷式

在之前,先讲一下Activity的启动模式:SingleTask

我们知道Activity有四种加载模式,而singleTask就是其中的一种,使用这个模式之后,当startActivity时,它先会在当前栈中查询是否存在Activity的实例,如果存在,则将其至于栈顶,并将其之上的所有Activity移除栈。我们打开一个app,首先是一个splash页面,然后会finish掉splash页面。跳转到主页。然后会在主页进行N次的跳转,期间会产生数量不定的Activity,有的被销毁,有的驻留在栈中,但是栈底永远是我们的HomeActivity。这样就让问题变得简单很多了。我们只需两步操作即可优雅的实现app的退出。

有了这么一个启动模式,就好办了,我们将退出的出口放在MainActivity中所有事都解决了。

那么这种方法为什么叫便捷式呢?这种方式代码量很少而且很好理解、优雅,而且市面上很多APP都是基于此实现的。我们在MainActivity中实现如下代码:

private boolean isExit;

  /**
   * 双击返回键退出
   */
  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {

      if (keyCode == KeyEvent.KEYCODE_BACK) {
          if (isExit) {
              this.finish();

          } else {
              Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
              isExit = true;
              new Handler().postDelayed(new Runnable() {
                  @Override
                  public void run() {
                      isExit= false;
                  }
              }, 2000);
          }
          return true;
      }

      return super.onKeyDown(keyCode, event);
  }
复制代码

不要着急,不要以为就完了,还有很重要的一步:将MainActivity设置为singleTask。

<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>
复制代码

上面这种方法就是我个人认为最简便的方式了,这也符合有些要求按2次退出。

3.广播式

我相信很多的老铁是使用的广播式,毕竟很方便,先上代码,再说利弊。

public abstract class BaseActivity extends Activity {

   private static final String ACTION = "action.exit";

   private ExitReceiver exitReceiver = new ExitReceiver();

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       IntentFilter filter = new IntentFilter();
       filter.addAction(ACTION);
       registerReceiver(exitReceiver, filter);
   }

   @Override
   protected void onDestroy() {
       super.onDestroy();
       unregisterReceiver(exitReceiver);
   }

   class ExitReceiver extends BroadcastReceiver {

       @Override
       public void onReceive(Context context, Intent intent) {
           BaseActivity.this.finish();
       }

   }

}
复制代码

最后再需要退出的地方,发送一个广播就可以了,注意Action和注册的相同就可以了。

但是个人觉得这种方式还是太耗性能,毕竟广播是进程间通信,我们一个退出APP功能不是特别的有必要。

4.SingleTask式

简单解释一下SingleTask这种启动模式的两个特点: 清除堆栈中处于当前Activity上方的Activity 堆栈中含有你要启动的Activity时,不会重新创建。

假设我们的MainActivity是使用的SingleTask的启动模式,假设我跳转到了其他的页面,然后使用startActivity(this,MainActivity.class)的方式再次启动MainActivity,这时MainActivity走到onNewIntent()方法,然后按照生命周期onRestart()——>onStart()——>onResume(),MainActivity不会重新创建。

既然有这么一个特点我们就可以分三步来退出APP:

第一步:MainActivity设置为SingleTask。

android:launchMode="singleTask"
复制代码

第二步:重写MainActivity中的onNewIntent方法

private static final String TAG_EXIT = "exit";

   @Override
   protected void onNewIntent(Intent intent) {
       super.onNewIntent(intent);
       if (intent != null) {
           boolean isExit = intent.getBooleanExtra(TAG_EXIT, false);
           if (isExit) {
               this.finish();
           }
       }
   }
复制代码

第三步:需要退出时在Intent中添加退出的tag

Intent intent = new Intent(this,MainActivity.class);
       intent.putExtra(MainActivity.TAG_EXIT, true);
       startActivity(intent);
复制代码

虽然这种方式简单、便捷,但还有弊端:当我们需要退出的时候,假如是在其他的Activity中退出,这时MainActivity要走一段生命周期的方法,有点浪费。

5.进程式

1.android.os.Process.killProcess(android.os.Process.myPid());
   
2.System.exit(0);

3.ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
   manager.killBackgroundProcesses(getPackageName());
复制代码

这三种方式都能够达到杀死进程的效果,直接退出APP,但是这种太暴力了不推荐使用,而且使用体验不好。不知道是不是华为手机问题,我用华为P10 Plus使用这种方式退出的时候要白屏、闪屏一下,反正就是不建议使用这种方式。

总结

其实严格来说,还有一种方式就是抛异常让APP强制退出,因为感觉用的人不多就没有细说。 上面的几种方式中,最不推荐的就是最后第五种方式,暴力而且用户体验不好。大家在项目中看着需求、以及自己习惯的方式来选择就好,今天就到这里了。

温馨提示:

我创建了一个技术交流群,群里有各个行业的大佬都有,大家可以在群里畅聊技术方面内容,以及文章推荐;如果有想加入的伙伴加我微信号【luotaosc】备注一下“加群”

另外关注公众号,还有一些个人收藏的视频:

回复“Android” ,获取Android视频链接。

回复“Java” ,获取Java视频链接。

回复“C++” ,获取C++视频链接。

回复“C” ,获取C视频链接。

回复“Python” ,获取Python视频链接等等。

原创文章不易,如果觉得写得好,扫码关注一下点个赞,是我最大的动力。

关注我,一定会有意想不到的东西等你: 每天专注分享Android干货

备注:程序圈LT

文章分类
Android