前言

现在几乎所有的app都有退出程序的功能(最常见的就是在项目主Activity中连续点击两次返回按钮退出app)至于具体如何实现退出功能,网上有罗列出以下4种方式:

  1. 容器式
  2. SingleTask式
  3. 广播式
  4. 进程式

个人比较推荐使用弱引用的容器式,应该也是目前使用最多的方式,在SingleTask式中本人又根据具体的项目需求进行了细分,有在主Activity实现退出功能的懒人式,和在非主Activity中实现退出功能的通用式,基本涵盖了大多数app退出功能的实现需求,具体如何实现请耐心往下看。
下面我们一一来进行介绍:

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);
 }
 
}

对应的全局的Activity的管理类如下:

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的强引用,也就是说当某个Activity异常退出时,如果ActivityUtils没有及时释放掉引用,就会导致内存问题,而且代码量多,不够优雅,诸多不便。

针对以上容器式实现存在的内存问题,我们可以使用弱引用的方式来进行避免,具体实现如下:

全局的Activity管理类:

public class ActivityManager {

    private Stack<WeakReference<Activity>> mActivityStack;
    private static volatile ActivityManager mInstance = new ActivityManager();

    private ActivityManager() {

    }

    public static ActivityManager getInstance() {
        if (mInstance == null) {
            synchronized (ActivityManager.class) {
                if (mInstance == null) {
                    mInstance = new ActivityManager();
                }
            }
        }
        return mInstance;

    }

    /**
     * 入栈
     * @param activity activity实例
     */
    public void addActivity(Activity activity) {
        if (mActivityStack == null) {
            mActivityStack = new Stack<>();
        }
        mActivityStack.add(new WeakReference<>(activity));
    }

    /**
     * 出栈
     * @param activity
     */
    public void removeActivity(Activity activity) {
        if (mActivityStack != null) {
            mActivityStack.remove(new WeakReference<>(activity));
        }
    }

    /**
     * 检查弱引用是否释放,若释放,则从栈中清理掉该元素
     */
    public void checkWeakReference() {
        if (mActivityStack != null) {
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity temp = activityReference.get();
                if (temp == null) {
                    it.remove();// 使用迭代器来进行安全的加锁操作
                }
            }
        }
    }

    /**
     * 获取当前Activity
     * @return 当前(栈顶)activity
     */
    public Activity currentActivity() {
        checkWeakReference();
        if (mActivityStack != null && !mActivityStack.isEmpty()) {
            return mActivityStack.lastElement().get();
        }
        return null;
    }

    /**
     * 结束除当前activtiy以外的所有activity
     * @param activtiy 不需要结束的activity
     */
    public void finishOtherActivity(Activity activtiy) {
        if (mActivityStack != null && activtiy != null) {
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity temp = activityReference.get();
                if (temp == null) {
                    // 清理掉已经释放的activity
                    it.remove();
                    continue;
                }
                if (temp != activtiy) {
                    // 使用迭代器来进行安全的加锁操作
                    it.remove();
                    temp.finish();
                }
            }
        }
    }

    /**
     * 结束除指定activtiy以外的所有activity
     * @param cls 指定的某类activity
     */
    public void finishOtherActivity(Class<?> cls) {
        if (mActivityStack != null) {
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity activity = activityReference.get();
                if (activity == null) {
                    // 清理掉已经释放的activity
                    it.remove();
                    continue;
                }
                if (!activity.getClass().equals(cls)) {
                    // 使用迭代器来进行安全的加锁操作
                    it.remove();
                    activity.finish();
                }
            }
        }
    }

    /**
     * 结束当前Activity
     */
    public void finishActivity() {
        Activity activity = currentActivity();
        if (activity != null) {
            finishActivity(activity);
        }
    }

    /**
     * 结束指定的Activity
     * @param activity 指定的activity实例
     */
    public void finishActivity(Activity activity) {
        if (activity != null) {
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity temp = activityReference.get();
                if (temp == null) {
                    // 清理掉已经释放的activity
                    it.remove();
                    continue;
                }
                if (temp == activity) {
                    it.remove();
                }
            }
            activity.finish();
        }
    }

    /**
     * 结束指定类名的所有Activity
     * @param cls 指定的类的class
     */
    public void finishActivity(Class<?> cls) {
        if (mActivityStack != null) {
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity activity = activityReference.get();
                if (activity == null) {
                    // 清理掉已经释放的activity
                    it.remove();
                    continue;
                }
                if (activity.getClass().equals(cls)) {
                    it.remove();
                    activity.finish();
                }
            }
        }
    }

    /**
     * 结束所有Activity
     */
    public void finishAllActivity() {
        if (mActivityStack != null) {
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity activity = activityReference.get();
                if (activity != null) {
                    activity.finish();
                }
            }
            mActivityStack.clear();
        }
    }

}

BaseActivity中:

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 添加进全局的activity管理栈
        ActivityManager.getInstance().addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //将该activity从栈中移除
        ActivityManager.getInstance().removeActivity(this);
    }
    
}

当需要退出应用的时候直接调用ActivityManager中的关闭Activity的方法即可,如下:

销毁指定的activity:ActivityManager.getInstance().finishActivity()
退出应用调用 ActivityManager.getInstance().finishAllActivity()

2.SingleTask式

该模式下又分为两种情况:

  1. 如果项目需求是在主Activity中实现退出app的功能 — 懒人式
  2. 项目需求在其他某一非主Activity的页面实现退出功能 — 通用式

我们先来回顾下Activity的四种加载模式中的SingleTask模式:

我们知道Activity有四种加载模式,而singleTask就是其中的一种,使用这个模式之后,当startActivity时,它先会在当前栈中查询是否存在Activity的实例,如果存在,则将其至于栈顶,并将其之上的所有Activity移除栈。我们打开一个app,首先是一个splash页面,然后会finish掉splash页面。跳转到主页。然后会在主页进行N次的跳转,期间会产生数量不定的Activity,有的被销毁,有的驻留在栈中,但是栈底永远是我们的HomeActivity。

懒人式的具体实现

根据上面对SingleTask加载模式的分析可知,如果我们项目需求是要在HomeActivity即主Activity中实现退出功能,那么我们仅仅只需简单的两步:
1.首先在主Activity添加具体的退出代码:

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);
  }

2.在清单文件中设置主Activity的加载模式为SingleTask:

<activity
      android:name=".MainActivity"    
      android:launchMode="singleTask"  />

通用式的具体实现

对于以SingleTask加载的Activity有如下特点:

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

根据以上特点,我们就可以分三步实现在非主Activity中退出activity的功能:
假如我们从主界面MainActivity跳转到了FirstActivity,又从FirstActivity跳转到了SecondActivity,现在需要在SecondActivity中实现退出app的功能:
1.设置MainActivity的加载模式为SingleTask:

<activity
      android:name=".MainActivity"    
      android:launchMode="singleTask"  />

2.实现MainActivity中的onNewIntent方法,实现退出APP的逻辑:

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        String tag = intent.getStringExtra("EXIT_TAG");
        if (tag != null&& !TextUtils.isEmpty(tag)) {
            if ("SINGLETASK".equals(tag)) {//退出程序
                finish();
            }
        }
    }

注意:此处实现的是MainActivity中的onNewIntent方法,而非SecondActivity中的。
3.第二步里面的tag用来标识关闭app的,在secondActivity中退出APP调用startActivity的时候需要传入。
secondActivity中相关代码如下:

Intent intent = new Intent(this, MainActivity.class);
                intent.putExtra("EXIT_TAG", "SINGLETASK");
                startActivity(intent);

通过以上三步就解决了在非主Activity优雅安全的退出APP的问题。

3.广播式

BaseActivity中代码如下:

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.进程式

1.android.os.Process.killProcess(android.os.Process.myPid());
   
2.System.exit(0);
 
3.ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
   manager.killBackgroundProcesses(getPackageName());

以上三种方式都能够达到杀死进程,直接退出APP的效果,但是这种太暴力了不推荐使用,而且用户体验不好,所以也不推荐使用。