这是Android常见的几种退出应用的方法,在此做一个总结,这几种方法各有利弊,可以自己去尝试一下。

一、容器式

建立一个全局容器,把所有的Activity存储起来,退出时循环遍历finish所有Activity


import android.app.Activity;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by LY on 2017/6/19.
 * 随时随地的退出程序
 * 通过一个List来暂存活动,然后提供了一个addActivity()方法用于向List中添加一个活动,
 * 提供了一个removeActivity()方法用于从List中移除活动,
 * 最后提供了一个finishAllActivity()方法用于将List中存储的活动全部都销毁掉。
 *
 * 使用方式:
 * 在BaseActivity中的onCreate()方法中调用addActivity()方法,表明将当前正在创建的活动添加到活动管理器里。
 * 然后在BaseActivity中的onDestory()方法中调用removeActivity()方法,,表明将马上要销毁的活动从活动管理中移除。
 * 从此以后,不管你想在什么地方退出程序,只需要调用ActivityCollectorUtil.finishAllActivity()方法就可以了。
 */

public class ActivityCollectorUtil {

    public static List<Activity> activities = new ArrayList<Activity>();

    /**
     * 添加新的activity到集合中
     *
     * @param activity
     */
    public static void addActivity(Activity activity) {
        activities.add(activity);
    }

    /**
     * 从集合中移除相应的activity
     *
     * @param activity
     */
    public static void removeActivity(Activity activity) {
        activities.remove(activity);
    }

    /**
     * 关闭所有的活动(activity),即退出程序
     */
    public static void finishAllActivity() {
        for (Activity activity : activities) {
            if (!activity.isFinishing()) {
                activity.finish();
            }
        }
    }
}
//使用方式
public class BaseActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityCollectorUtil.addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollectorUtil.removeActivity(this);
    }
}

这种方法比较简单,是目前许多人常用的, 但是可以看到activityStack持有这Activity的强引用,也就是说当某个Activity异常退出时,activityStack没有即使释放掉引用,就会导致内存问题。

二、任务栈式

利用一个单例模式的Activity栈来管理所有Activity

  • 自定义 Application类,储存每一个Activity,并实现关闭所有Activity的操作
public class MyApplication extends Application {    
    private List<Activity> activityList = new LinkedList<Activity>();
    private static MyApplication instance;
    private MyApplication() {
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
    }
    
    //单例模式中获取唯一的MyApplication实例
    public static MyApplication getInstance() {
        if(null == instance) {
            instance = new MyApplication();
        }
        return instance;
    }
    
   //添加Activity到容器中
    public void addActivity(Activity activity)  {
        activityList.add(activity);
    }
    
   //遍历所有Activity并finish
    public void exit() {
        for(Activity activity:activityList) {
            activity.finish();
        }       
        activityList.clear();
    }
}
  • 在父类BaseActivity中添加继承子类Activity到栈中
public class BaseActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 添加Activity到堆栈
        MyApplication.getInstance().addActivity(this);
    }
    ...
}
  • 在需要结束所有Activity的时候调用exit方法
MyApplication.getInstance().exit();

存在问题:同方法一

三、广播式

通过在BaseActivity中注册一个广播,当退出时发送一个广播,finish退出。

/**
 * Created by LY on 2017/6/19.
 * 通过广播的方式退出应用
 */
public class BaseActivity extends Activity {

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

    private ExitReceiver exitReceiver = new ExitReceiver();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        IntentFilter filter = new IntentFilter();
        filter.addAction(EXITACTION);
        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();
        }

    }

}

发送广播退出app

public class MainActivity extends BaseActivity {
    private long exitTime = 0;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
// 物理返回键,双击退出
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
            if ((System.currentTimeMillis() - exitTime) > 2000) {
                Toast.makeText(MainActivity.this, "再按一次退出程序", Toast.LENGTH_SHORT).show();
                exitTime = System.currentTimeMillis();
            } else {
                //发送广播退出程序
                Intent intent = new Intent("com.xxx.BaseActivity");
                intent.putExtra(EXITACTION, 1);
                sendBroadcast(intent);
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

四、 进程式

  • android.os.Process.killProcess(android.os.Process.myPid());
    可以杀死当前应用活动的进程,这一操作将会把所有该进程内的资源(包括线程全部清理掉)。当然,由于ActivityManager时刻监听着进程,一旦发现进程被非正常Kill,它将会试图去重启这个进程。
  • System.exit(0);正常退出
    System.exit(1);//非正常退出
    Java中结束进程的方法,调用它将关闭当前的JVM虚拟机。

这两种都能达到同样的效果,但是在模拟器上都会弹出 Unfortunately , XXX has stopped 消息提示框,但确实能退出应用。部分真机直接失效,只能finish当前Activity(比如我手上这台小米note,国产的几款ROM fw层改动太多,使用这种方式需慎重) 。
KillProcess() 和 System.exit(),许多人都使用过,当你栈里只有一个Activity的时候,这个措施是行之有效的。但当关闭多个Activity的时候,栈里有多个Activity时,这两个方法就不起作用了。
因为通过杀进程方式退出,会被系统认为异常退出,会保存应用的一些状态信息比如Activity运行栈,然后会恢复这个应用。当恢复一个Android应用程序时,会先从栈里面移除异常的Activity,相当于Back键操作。

五、 任务管理器

系统将终止一切和这个程序包关联的,所有共享同一uid的process全部杀掉,还会停止相关的服务以及移除所有的Activity,并且会发送一个广播。

<uses-permission android:name="android.permission.RESTART_PACKAGES"/>
//注意在Android 2.2(API 8)之后,restartPackage方法已经过时
ActivityManager am = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);
am.restartPackage(getPackageName());

但是在Android 2.2(API 8)之后,restartPackage方法已经过时,不可以将应用程序结束,需要使用ActivityManager类的 killBackgroundProcesses方法。

<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>  
ActivityManager am = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);
am.killBackgroundProcesses(getPackageName());

使用时需要注意:该方法虽然可以立即杀死与指定包相关联的所有后台进程,但是这些进程如果在将来某一时刻需要使用,便会重新启动。

六、 广播+singletask

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

  • 在HomeActivity注册一个退出广播,和第二个广播式一样,但是这里只需要在HomeActivity一个页面注册即可。

  • 设置HomeActivity的启动模式为singleTask。

当我们需要退出的时候只需要startActivity(this,HomeActivity,class), 再发送一个退出广播。上面代码首先会把栈中HomeActivity之上的所有Activity移除出栈,然后接到广播finish自己。一切OK ! 没有弹框,不用考虑机型Rom适配。不会有内存问题。

七、singletask简易版

第五种注册广播的方式略显麻烦,有一种更简单的方式,思路也很简单,
* 设置MainActivity的加载模式为singleTask
* 重写MainActivity中的onNewIntent方法
* 需要退出时在Intent中添加退出的tag

//第一步,设置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();
            }
        }
    }

//第三步,调用退出方法。
/**退出程序*/
protected void exit() {
    // 这里使用clear + new task的方式清空整个任务栈,只保留新打开的Main页面
    // 然后Main页面接收到退出的标志位exit=true,finish自己,这样就关闭了全部页面
    Intent intent = new Intent(this, MainActivity.class);
    intent.putExtra("exit", true);
    startActivity(intent);
}

八、懒人式

这种方式更加简单,只需要如下两步操作
1、将MainActivity设置为singleTask
2、将退出出口放置在MainActivity
我们可以看到很多应用都是双击两次home键退出应用,就是基于这样的方式来实现的,这里在贴一下如何处理连续两次点击退出的源码

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

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

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

        return super.onKeyDown(keyCode, event);
    }

九、退回系统桌面

Android应用开发中,有一种场景,就是我们不希望用户直接按Back键退出Activity,而是希望应用隐藏到后台的假退出,类似于按Home键的效果。(例如QQ、微信等、音乐播放器类软件等)。

  • 方法一(java):
/**退出程序**/
protected void exit() {
    Intent startMain = new Intent(Intent.ACTION_MAIN);
    startMain.addCategory(Intent.CATEGORY_HOME);
    startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(startMain);
    System.exit(0);
}
  • 方法二(xml):
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xxx.xxx"   
    android:versionCode="1"
    android:versionName="1.0.1">
  <application>     
    <activity
        android:name="com.xxx.xxx.MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:clearTaskOnLaunch="true"
        android:stateNotNeeded="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.HOME" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity> 
   ...
  </application>
</manifest>

十、监听式

从Android 4.0(API 14)开始,Application中多了一个可以设置全局监听Activity生命周期的方法:registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback),其中传入的参数 ActivityLifecycleCallbacks能得到全局所有Activity生命周期的回调,所以我们可以从Application中全局监听所有Activity并对其进行管理。

public class MyApplication extends Application {
    protected static Context context;   

    /**
     * 维护Activity 的list
     */
    private static List<Activity> mActivitys = Collections.synchronizedList(new LinkedList<Activity>());

    @Override
    public void onCreate() {
        super.onCreate();
        context = this.getApplicationContext();
        registerActivityListener();
    }

    public static Context getContext() {
        return context;
    }

    /**
     * @param activity 作用说明 :添加一个activity到管理里
     */
    public void pushActivity(Activity activity) {
        mActivitys.add(activity);
    }

    /**
     * @param activity 作用说明 :删除一个activity在管理里
     */
    public void popActivity(Activity activity) {
        mActivitys.remove(activity);
    }

    /**
     * get current Activity 获取当前Activity(栈中最后一个压入的)
     */
    public static Activity currentActivity() {
        if (mActivitys == null||mActivitys.isEmpty()) {
            return null;
        }
        Activity activity = mActivitys.get(mActivitys.size()-1);
        return activity;
    }

    /**
     * 结束当前Activity(栈中最后一个压入的)
     */
    public static void finishCurrentActivity() {
        if (mActivitys == null||mActivitys.isEmpty()) {
            return;
        }
        Activity activity = mActivitys.get(mActivitys.size()-1);
        finishActivity(activity);
    }

    /**
     * 结束指定的Activity
     */
    public static void finishActivity(Activity activity) {
        if (mActivitys == null||mActivitys.isEmpty()) {
            return;
        }
        if (activity != null) {
            mActivitys.remove(activity);
            activity.finish();
            activity = null;
        }
    }

    /**
     * 结束指定类名的Activity
     */
    public static void finishActivity(Class<?> cls) {
        if (mActivitys == null||mActivitys.isEmpty()) {
            return;
        }
        for (Activity activity : mActivitys) {
            if (activity.getClass().equals(cls)) {
                finishActivity(activity);
            }
        }
    }

    /**
     * 按照指定类名找到activity
     *
     * @param cls
     * @return
     */
    public static Activity findActivity(Class<?> cls) {
        Activity targetActivity = null;
        if (mActivitys != null) {
            for (Activity activity : mActivitys) {
                if (activity.getClass().equals(cls)) {
                    targetActivity = activity;
                    break;
                }
            }
        }
        return targetActivity;
    }

    /**
     * @return 作用说明 :获取当前最顶部activity的实例
     */
    public Activity getTopActivity() {
        Activity mBaseActivity = null;
        synchronized (mActivitys) {
            final int size = mActivitys.size() - 1;
            if (size < 0) {
                return null;
            }
            mBaseActivity = mActivitys.get(size);
        }
        return mBaseActivity;

    }

    /**
     * @return 作用说明 :获取当前最顶部的acitivity 名字
     */
    public String getTopActivityName() {
        Activity mBaseActivity = null;
        synchronized (mActivitys) {
            final int size = mActivitys.size() - 1;
            if (size < 0) {
                return null;
            }
            mBaseActivity = mActivitys.get(size);
        }
        return mBaseActivity.getClass().getName();
    }

    /**
     * 结束所有Activity
     */
    public static void finishAllActivity() {
        if (mActivitys == null) {
            return;
        }
        for (Activity activity : mActivitys) {
            activity.finish();
        }
        mActivitys.clear();
    }

    /**
     * 退出应用程序
     */
    public  static void appExit() {
        try {
            finishAllActivity();
        } catch (Exception e) {
        }
    }

    private void registerActivityListener() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                    /**
                     *  监听到 Activity创建事件 将该 Activity 加入list
                     */
                    pushActivity(activity);
                }

                @Override
                public void onActivityStarted(Activity activity) {

                }

                @Override
                public void onActivityResumed(Activity activity) {

                }

                @Override
                public void onActivityPaused(Activity activity) {

                }

                @Override
                public void onActivityStopped(Activity activity) {

                }

                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

                }

                @Override
                public void onActivityDestroyed(Activity activity) {
                    if (null==mActivitys||mActivitys.isEmpty()) {
                        return;
                    }
                    if (mActivitys.contains(activity)) {
                        /**
                         *  监听到 Activity销毁事件 将该Activity 从list中移除
                         */
                        popActivity(activity);
                    }
                }
            });
        }
    }

}

十一、容器式升级版

跟容器式思路一样,添加了软应用,解决内存泄露问题。

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class ActivityManager {

    /**
     * 注意,此处为单例模式,在BaseActivity中,只会返回一个对象。否则,每次被继承的BaseActivity在子Activity被创建的时候,
     * 都会得到一个新的对象。每个新的对象下,又会创建自己的HashMap,效果就是,一个HashMap只存了一个activity,
     * 显然与我们想要的结果不一样。
     * 所以,必须使用单例模式
     */
    
    private static ActivityManager activityManager;

    public static ActivityManager getActivityManager() {
        if (activityManager == null) {
            activityManager = new ActivityManager();
        }
        return activityManager;
    }

    //此处,可有可无。
    private ActivityManager() {
    }

    /**
     * task map,用于记录activity栈,方便退出程序(这里为了不影响系统回收activity,所以用软引用)
     */
    private final HashMap<String, SoftReference<Activity>> taskMap = new HashMap<String, SoftReference<Activity>>();

    /**
     * 往应用task map加入activity
     */
    public final void putActivity(Activity atv) {
        taskMap.put(atv.toString(), new SoftReference<Activity>(atv));
        Log.i("PutActivity", "" + atv);
    }

    /**
     * 往应用task map加入activity
     */
    public final void removeActivity(Activity atv) {
        taskMap.remove(atv.toString());
    }

    /**
     * 清除应用的task栈,如果程序正常运行这会导致应用退回到桌面
     */
    public final void exit() {
        for (Iterator<Entry<String, SoftReference<Activity>>> iterator = taskMap
                .entrySet().iterator(); iterator.hasNext();) {
            SoftReference<Activity> activityReference = iterator.next()
                    .getValue();
            Activity activity = activityReference.get();
            Log.i("ActivityList", "" + activity);
            if (activity != null) {
                activity.finish();
            }
        }
        taskMap.clear();
    }

}

创建自己的根activity,重写onCreate与onDestory

import android.app.Activity;
import android.os.Bundle;

public class BaseActivity extends Activity {

    private ActivityManager manager = ActivityManager.getActivityManager();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        manager.putActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        manager.removeActivity(this);
    }

    public void exit() {
        manager.exit();
    }

}

以后创建的activity都继承这个根activity就可以了,调用exit()退出应用如下:

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class FragmentsActivity extends BaseActivity {
    private Button exit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment);

        exit = (Button) findViewById(R.id.exit);
        exit.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                exit();
            }
        });

    }

}

总结

以上即是Android中常用的退出应用的方法,还有一个抛异常来退出app的我就没有写了,因为那个实在不怎么的。这些方法各有利弊,有时间可以自己尝试下。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐