Android退出finishAll关闭所有Activity

前言

查看了太多网上错误的例子,因此想借此经验让大家明白优雅的退出APP的过程。

1.功能需求

公司要开发一款android APP,要求能按系统的‘退出键’进行退出,退出键退出很简单。

 @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME) {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    ActivityManager.getInstance().exitApp();
                }
            }, 500);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

KeyEvent.KEYCODE_BACK,表示用户按了系统返回键,

return true;表示拦截了该事件,不再向下执行系统的super.onKeyDown(keyCode, event);逻辑,当然如果业务需要,可以继续执行系统逻辑。
ActivityManager.getInstance().exitApp();

package com.yys.utils;
 
import android.app.Activity;
import android.app.Application;
 
import java.lang.ref.WeakReference;
import java.util.Stack;
 
/**
 * Activity管理类
 * <p>
 * 添加/删除 建议在{@link Application#registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks)}中统一处理
 * (此方法比在BaseActivity中处理要好)
 */
public class ActivityManager {
    private static Stack<WeakReference<Activity>> mActStack = new Stack<>();
 
    private static class Singleton {
        private static final ActivityManager INSTANCE = new ActivityManager();
    }
 
    public static ActivityManager getInstance() {
        return Singleton.INSTANCE;
    }
 
    private ActivityManager() {
    }
 
    /***  添加 建议在Application中统一处理 */
    public void add(Activity activity) {
        mActStack.add(new WeakReference<>(activity));
    }
 
    /***  移除 建议在Application中统一处理 */
    public void remove(Activity activity) {
        for (WeakReference<Activity> temp : mActStack) {
            if (isEqualsActivity(temp, activity)) {
                mActStack.remove(temp);
                break;
            }
        }
    }
 
    /**
     * 获取当前Activity数量
     *
     * @return
     */
    public int getCount() {
        return mActStack.size();
    }
 
    /**
     * 栈内是否包含此activity
     *
     * @param cls
     * @return
     */
    public boolean isContains(Class<?> cls) {
        for (WeakReference<Activity> temp : mActStack) {
            if (isEqualsActivity(temp, cls)) {
                return true;
            }
        }
        return false;
    }
 
 
    /**
     * 查找指定Activity 默认第一个
     *
     * @param cls
     * @return 未找到则返回 null
     */
    public <T extends Activity> T find(Class cls) {
        return findFirst(cls);
    }
 
    /**
     * 查找指定Activity 第一个
     *
     * @param cls
     * @return
     */
    public <T extends Activity> T findFirst(Class cls) {
        for (WeakReference<Activity> temp : mActStack) {
            if (isEqualsActivity(temp, cls)) {
                return (T) temp.get();
            }
        }
 
        return null;
    }
 
    /**
     * 查找指定Activity 最后一个
     *
     * @param cls
     * @return
     */
    public <T extends Activity> T findLast(Class cls) {
        for (int i = mActStack.size() - 1; i >= 0; i--) {
            WeakReference<Activity> temp = mActStack.get(i);
            if (isEqualsActivity(temp, cls)) {
                return (T) temp.get();
            }
        }
 
        return null;
    }
 
    /**
     * 获取当前(即最后一个) Activity
     *
     * @return
     */
    public <T extends Activity> T getCurrent() {
        if (mActStack.lastElement() != null) {
            return (T) mActStack.lastElement().get();
        }
        return null;
    }
 
    private boolean isEqualsActivity(WeakReference<Activity> temp, Class cls) {
        if (temp != null && temp.get() != null && temp.get().getClass().equals(cls)) {
            return true;
        }
        return false;
    }
 
    private boolean isEqualsActivity(WeakReference<Activity> temp, Activity activity) {
        if (temp != null && temp.get() != null && temp.get() == activity) {
            return true;
        }
        return false;
    }
 
    /**
     * 结束指定Activity
     *
     * @param activity
     */
    public void finish(Activity activity) {
        if (activity != null && !activity.isFinishing()) {
            activity.finish();
        }
        // remove(activity);//这个可以不用的 记得在Application中调用
    }
 
    /**
     * 结束指定Activity
     * 注:当栈中可能包含多个该Activity时,该方法会将所有的该Activity都finish
     *
     * @param cls
     */
    public void finish(Class cls) {
        for (WeakReference<Activity> temp : mActStack) {
            if (isEqualsActivity(temp, cls)) {
                finish(temp.get());
            }
        }
    }
 
    /**
     * 结束此Activity之前的所有Activity(不包括当前的 ,结束当前需手动) 最终显示此Activity
     * 1-2-3  * 4-5
     * 1-2  * 4-5
     * 1  * 4-5
     * * 4-5
     *
     * @param cls
     */
    public void finishBefore(Class cls) {
        boolean isFound = false;
        for (int i = mActStack.size() - 1; i >= 0; i--) {
            WeakReference<Activity> temp = mActStack.get(i);
            if (isFound) {
                if (temp != null && temp.get() != null) {
                    finish(temp.get());
                }
            } else if (isEqualsActivity(temp, cls)) {
                isFound = true;
            }
        }
    }
 
    /**
     * 结束此Activity之后的所有Activity(不包括当前的 ,结束当前需手动) 最终显示此Activity
     * 1-2-3 * 4-5
     * 1-2-3 * 5
     * 1-2-3 *
     *
     * @param cls
     */
    public void finishAfter(Class cls) {
        boolean isFound = false;
        for (WeakReference<Activity> temp : mActStack) {
            if (isFound) {
                if (temp != null && temp.get() != null) {
                    finish(temp.get());
                }
            } else if (isEqualsActivity(temp, cls)) {
                isFound = true;
            }
        }
    }
 
 
    public void finishAll() {
        for (int i = 0; i < mActStack.size(); i++) {
            if (mActStack.size() > 0 && mActStack.get(i) != null) {
                mActStack.peek();
                finish(mActStack.get(i).get());
                i--;//删除完后索引减1,保证集合正常遍历
            }
        }
    }
 
    public void exitApp() {
        finishAll();
 
    }
}
 

重点方法finishAll()

(1)这里在重申一下for循环的执行逻辑

1.int i = 0;

2.i < mActStack.size();

3.{循环语句块}

4.i++;

5.i < mActStack.size();

6.{循环语句块}

7..i++;

... ...

当不满足条件.i < mActStack.size();时,语句退出

(2)问题点在于Activity栈Stack,是一个集合,在集合中移除对象或添加对象会导致集合ConcurrentModificationException

原因:

这是并发修改异常错误,经过网上搜索了解到,原来是集合遍历原理导致的,具体原因是这样的:不管是哪种方式的集合遍历方法,当我们在遍历某个集合的时候,Collection的实现并没有同步化,如果在多线程应用程序中出现同时访问,而且出现修改操作的时候都要求外部操作同步化;调用遍历操作获得的遍历对象在多线程修改集合的时候也自动失效,并抛出java.util.ConcurrentModificationException。这种实现机制是fail-fast,对外部 的修改并不能提供任何保证。遍历对象在被创建的时候,同时创建了一张单链的索引表,指针指向原始数据对象,只能顺序读取,不能逆向操作,而set、list等集合是动态、可变的数据结构;当原始对象改变时,索引并为改变,因此,索引指针继续移动的时候,找不到要迭代的对象就会报错。

(3)i--;//删除完后索引减1,保证集合正常遍历,当每次执行完一个Activity退出后,初始索引又回到0,保证每次只取栈第一个的Activity调用finish。

(4)判断 mActStack.size() > 0也很关键,不然java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 0,原因

因为finish调用界面销毁并不是立即执行完成的,mActStack可能还存在元素但是正在销毁,当销毁完成后,集合自然也就为空集合了,这时候再取0的元素自然会报错。

自测可用。
————————————————

原文链接:https://blog.csdn.net/baidu_30084597/article/details/108598915

猜你喜欢

转载自blog.csdn.net/Jushuzhan/article/details/127064640