利用Activity生命周期变化判断Activity是否处于前台

1. Activity生命周期及对应表现

 onCreate Activity第一次创建
 onStart    Activity可见
 onResume Activity进入前台栈顶
 onPause  Activity不处于前台栈顶(被结束,或者有新界面压入)
 onStop Activity不可见(若上层界面是透明对话框,对话框下的界面是不会进入onStop的)
 onDestroy Activity开始销毁

2. 判断应用是否处于前台

 **需求:**
 开发中我们经常会遇到APP在后台运行时被结束,或者直接就是用户清理内存下了杀手,这导致我们程序的数据丢失,无法再下次启动时衔接进度,如常见的游戏开发就是如此,直接就没存档怎么玩。
 因此我们希望在应用程序进入后台时立即进行自动存档,以便下次恢复程序运行进度。

**整理下思路:**
应用中只要有一个界面处于前台,那么应用就还在前台运行,所以讲道理所有界面都用一个变量isForeGround,onCreate 、onResume时设置为true,onPause设置为false即可,那么判断所有界面isForeGround的状态即可得到程序当前是否在前台运行。
想法总是那么美好(简单),然而一个Activity A启动另一个Activity B时生命周期走的是AonPause BonCreate BonStart BonResume AonStop,再比如B结束(finish())后生命周期走的是 BonPause AonRestart AonStart....
如你们所见,在当前界面执行onPause之后才会开启另一个界面,在执行onPause时isForeGround = false,确切的说是所有界面的isForeGround 都为false。

此问题是由于界面跳转引起的,再引入一个全局变量openMyActivity,当跳转的是我们APP的界面时改值为true,跳转后界面进入onResume我们再把这个值设置为false,这样只要openMyActivity == true(跳转到我们的界面),那肯定是还处于前台,其他情况根据所有界面的isForeGround 来判断即可

**怎么判断即将打开的是我们APP的界面?**
我们将所有创建(onCreate)的界面存入集合中,如果界面销毁(onDestroy),则从集合中移除。当有一个界面finish(),我们判断集合长度是否大于1(是否还有另一个界面),如果有,那就是打开那个界面,此时应该设置openMyActivity = true。
那么对于startActivity进行跳转呢?这种显示跳转打开下个界面Intent中含有下个界面的class,我们取的class全类名,判断是否包含包名,如果包含包名则是打开我们的界面,此时openMyActivity设置为true。

这样我们先判断openMyActivity是否为true,是的话程序处于前台,否则判断所有界面isForeGround,如果有一个处于前台,则程序也处于前台,下面给出代码。
/**
 * Activity基类
 */

public class BaseActivity extends Activity implements ActivityControlUtils.IActivityControl {

    private boolean isFinish = false;//界面处于销毁中?
    private boolean isForeground = true;//界面处于前台?

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ActivityControlUtils.openMyActivity = true;
        ActivityControlUtils.regi(this);
        super.onCreate(savedInstanceState);
    }

 @Override
    protected void onRestart() {
        ActivityControlUtils.openMyActivity = true;
        super.onRestart();
    }

    @Override
    protected void onResume() {
        super.onResume();
        ActivityControlUtils.openMyActivity = false;
        isForeground = true;
    }

    @Override
    protected void onPause() {
        super.onPause();
        isForeground = false;
    }

    @Override
    public void finish() {
        //若之前还有打开的界面(关闭当前界面会打开之前的界面),标记为true
        if(ActivityControlUtils.getCurrActivityStackSize()>1){
            ActivityControlUtils.openMyActivity = true;
        }
        super.finish();
        isFinish = true;
    }

      @Override
    protected void onDestroy() {
        super.onDestroy();
        isFinish = true;
        ActivityControlUtils.unRegi(this);
    }

    @Override
    public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
        super.startActivityForResult(intent, requestCode, options);
        String className = intent.getComponent().getClassName();
        //如果要打开的界面属于本应用界面,则标记为true
        if (!TextUtils.isEmpty(className) && className.toLowerCase().contains(this.getApplication().getPackageName())) {
            ActivityControlUtils.openMyActivity = true;
        }
    }

 //----------------------------------------------------

    @Override
    public boolean isActivityFinish() {
        return isFinish;
    }

    @Override
    public boolean isActivityForeground() {
        return isForeground;
    }

    @Override
    public void finishActivity() {
        finish();
    }
}

/**
 * 界面控制工具 
 */

public class ActivityControlUtils {

    /**
     * Activity控制接口
     */
    public interface IActivityControl {
        boolean isActivityFinish();//界面是否结束

        boolean isActivityForeground();//界面是否处于前台

        void finishActivity();//结束界面
    }

    private static List iacList = new ArrayList<>();//界面集合
    public static boolean openMyActivity = false;//处于打开界面状态(包含准备打开一个本应用的新界面,或者从本应用的界面回到上一个界面)

  public static int getCurrActivityStackSize() {
        return iacList.size();
    }

    /**
     * 注册activity
     *
     * @param iac IActivityControl实现类实例
     */
    public static void regi(IActivityControl iac) {
        if (iac != null) {
            iacList.add(iac);
        }
    }

    /**
     * 注消activity
     *
     * @param iac IActivityControl实现类实例
     */
    public static void unRegi(IActivityControl iac) {
        if (iac != null) {
            iacList.remove(iac);
        }
    }

    /**
     * 程序是否在前台运行
     *
     * @return true 程序前台运行,false 程序后台运行
     */
    public static boolean isApplicationRunOnForeground() {
        //由于一个界面打开另一个界面是先执行onPause(此时所有界面都不处于前台)之后再执行的,
        // 所以要加上一个本应用界面正在打开的标识
        boolean result = false;
        if (openMyActivity) {//如果处于界面打开阶段,则肯定在前台
            result = true;
        } else {//不处于应用打开阶段,若界面有一个处于前台则,当前应用处于前台,否则处于后台
            for (IActivityControl iac : iacList) {
                result |= iac.isActivityForeground();
            }
        }
        return result;
    }

    /**
     * 退出所有界面
     */
    public static void exitAllActivity() {
        List tempList = new ArrayList<>();//界面集合
        tempList.addAll(iacList);
        for (IActivityControl iac : tempList) {
            iac.finishActivity();
        }
        tempList.clear();
    }

}

如上所见,只要全部Acticity都继承自BaseActivity,即可在Activity onPause时调用ActivityControlUtils.isApplicationRunOnForeground()得到当前是否在前台运行,如果是后台运行,此时已经可以对程序数据进行保存了。
只要是切出我们的app就能立即知道程序在后台运行。
本人小白,不喜勿喷,我也知道网上有两种获取程序是否前台运行的方法,就是不想拷贝,啦啦啦

你可能感兴趣的:(android,基础回顾)