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

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

常见的有6中方式:

  • 便捷式
  • 容器式
  • 广播式
  • SingleTask式
  • 进程式
  • activity 的管理Manager

实现方法

1.便捷式

在之前,先讲一下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 {
                ToastUtils.show("再按一次退出!");
                isExit = true;
                new Handler().postDelayed(() -> 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次退出。

2.容器式
容器式可能是我们最常见的方式之一了,主要通过创建一个全局的容器,把所有的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持有的引用没有被销毁会导致部分内存问题,而且代码量多,不够优雅,诸多不便。

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

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使用这种方式退出的时候要白屏、闪屏一下,反正就是不建议使用这种方式。

6.activity 的管理Manager

我们在Android应用中如果正确的管理activity,以便于我们拿到Activity的对象或者正确的退出app呢?下面提供一个Manger类来管理我们的Activity,方法可以根据自己的需求进行添加,思路也比较简单,我们的管理类实现ActivityLifecycleCallbacks接口在相对应的生命周期中执行需要的操作,例如添加和移除activity,同时我们需要是一种数据结构去保存activity,可以是ArrayList或HashMap,以便于我们去对这些activity进行管理。

/**
 * 类名称:MyActivityManager
 * 描  述: 提供退出应用的方法,实现Application.ActivityLifecycleCallbacks接口
 */
public class ActivityManager implements Application.ActivityLifecycleCallbacks {
    private ArrayList<WeakReference<Activity>> sActivity = new ArrayList();

    private ActivityManager() {
    }

    private static class ACTIVITY_MANAGER_INSTANCE {
        private static final ActivityManager ACTIVITY_MANAGER = new ActivityManager();
    }

    public static ActivityManager getInstance() {
        return ACTIVITY_MANAGER_INSTANCE.ACTIVITY_MANAGER;
    }

    private void add(Activity activity) {
        if (activity != null) {
            WeakReference<Activity> activityWeakReference = new WeakReference<>(activity);
            sActivity.add(activityWeakReference);
        }
    }

    private void remove(Activity activity) {
        for (int i = 0, size = sActivity.size(); i < size; i++) {
            WeakReference<Activity> activityWeakReference = sActivity.get(i);
            Activity innerActivity = activityWeakReference.get();
            if (innerActivity == activity) {
                sActivity.remove(activityWeakReference);
                break;
            }
        }
    }

    /**
     * 获取MainActivity
     *
     * @return
     */
    public MainActivity getMainActivity() {
        for (int i = 0, size = sActivity.size(); i < size; i++) {
            WeakReference<Activity> activityWeakReference = sActivity.get(i);
            Activity activity = activityWeakReference.get();
            if (activity instanceof MainActivity) {
                return (MainActivity) activity;
            }
        }
        return null;
    }


    /**
     * finish掉所有Activity
     */
    public void exitApp() {
        for (int i = 0, size = sActivity.size(); i < size; i++) {
            WeakReference<Activity> activityWeakReference = sActivity.get(i);
            Activity activity = activityWeakReference.get();
            if (activity != null) {
                activity.finish();
            }
        }
        if (sActivity != null && sActivity.size() > 0) {
            sActivity.clear();
        }
    }


    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        //activity  create时,添加activity
        add(activity);
    }

    @Override
    public void onActivityStarted(Activity activity) {
        //activity  start时,可以做一些操作,例如记录此activity回到前台的时间等

    }

    @Override
    public void onActivityResumed(final Activity activity) {
        //activity  resume时,可以做一些操作,例如让一些后台任务重新开启,或者app切换到前台的时间等
    }

    @Override
    public void onActivityPaused(Activity activity) {
        //activity  pause时,可以做一些操作,例如暂停一些后台任务
    }

    @Override
    public void onActivityStopped(Activity activity) {
        //activity  stop时,可以做一些操作,例如记录app切换到后台的时间等
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        //保存状态
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        //activity  destroy时,移除activity
        remove(activity);
    }
}

总结

上面的几种方式中,最不推荐的就是最后第五种方式,暴力而且用户体验不好。大家在项目中看着需求、以及自己习惯的方式来选择就好

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值