Android应用前后台切换的判断

       最近项目中有个要求,判断当前情况属于按Home键应用切到后台,以及点击桌面图标,应用重新进入前台的情况。Android中没有提供一个应用前后台切换的回调或广播,这个功能只能我们自己来处理。以前遇到这个问题的处理方式是,实现一个BaseActivity,然后让其他所有Activity都继承自它,然后在生命周期函数中做相应的检测。具体检测方法如下:

       在Activity的onStart和onStop方法中进行计数,计数变量为count,在onStart中将变量加1,onStop中减1,假设应用有两个Activity,分别为A和B。

       情况一、首先启动A,A再启动B:启动A,count=1,A启动B,生命周期的顺序为B.onStart->A.onStop,count的计数仍然为1。

       情况二、首先启动A,然后按Home键返回桌面:启动A,count=1,按Home键返回桌面,会执行A.onStop,count的计数变位0。

       从上面的两种情况看出,可以通过对count计数为0,来判断应用被从前台切到了后台。同样的,从后台切到前台也是类似的道理。具体实现看后面的代码。

       但是如果项目中不是所有的Activity都继承自同一个BaseActivity,就无法实现这个功能了。幸运的是,Android在API 14之后,在Application类中,提供了一个应用生命周期回调的注册方法,用来对应用的生命周期进行集中管理,这个接口叫registerActivityLifecycleCallbacks,可以通过它注册自己的ActivityLifeCycleCallback,每一个Activity的生命周期都会回调到这里的对应方法。其实这个注册方法的本质和我们实现BaseActivity是一样的,只是将生命周期的管理移到了Activity本身的实现中。

       具体使用方法如下:

public class MyApplication extends Application{
    public int count = 0;
    @Override
    public void onCreate() {
        super.onCreate();

        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

            @Override
            public void onActivityStopped(Activity activity) {
                Log.v("viclee", activity + "onActivityStopped");
                count--;
                if (count == 0) {
                    Log.v("viclee", ">>>>>>>>>>>>>>>>>>>切到后台  lifecycle");
                }
            }

            @Override
            public void onActivityStarted(Activity activity) {
                Log.v("viclee", activity + "onActivityStarted");
                if (count == 0) {
                    Log.v("viclee", ">>>>>>>>>>>>>>>>>>>切到前台  lifecycle");
                }
                count++;
            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
                Log.v("viclee", activity + "onActivitySaveInstanceState");
            }

            @Override
            public void onActivityResumed(Activity activity) {
                Log.v("viclee", activity + "onActivityResumed");
            }

            @Override
            public void onActivityPaused(Activity activity) {
                Log.v("viclee", activity + "onActivityPaused");
            }

            @Override
            public void onActivityDestroyed(Activity activity) {
                Log.v("viclee", activity + "onActivityDestroyed");
            }

            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                Log.v("viclee", activity + "onActivityCreated");
            }
        });
    }
}
       除此之外,有没有其他方法可以实现这个功能呢?

       应用切换到桌面的本质,其实就是将当前Activity所在的Task切到后台,而将桌面所在的Task切到前台。所以我们可以在当前页面的onStop方法中去检测当前最新的Activity运行栈,如果与本应用相同,说明只是启动了一个新的Activity,如果不相同,说明本应用被切到了后台。想想问什么要在onStop中检测,而不是onPause?这是由于A启动B,生命周期的执行顺序如下:A.onPause->B.onCreate->B.onStart->B.onResume->A.onStop,也就是说,在A的onStop方法中,B还没有创建,当然是检测不到的。

       由于不同的rom对桌面都会有定制,桌面应用的包名各不相同,通常的包名都类似于com.android.launcher2,包名具体是什么不会影响我们的功能。

       具体实现代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    public static final String TAG = "viclee";
    private boolean isCurrentRunningForeground = true;

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

        findViewById(R.id.btn).setOnClickListener(this);
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!isCurrentRunningForeground) {
            Log.v(TAG, ">>>>>>>>>>>>>>>>>>>切到前台 activity task");
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        isCurrentRunningForeground = isRunningForeground();
        if (!isCurrentRunningForeground) {
            Log.v(TAG, ">>>>>>>>>>>>>>>>>>>切到后台 activity task");
        }
    }

    public boolean isRunningForeground() {
        String packageName = getPackageName();
        String topActivityClassName = getTopActivityName(this);
        Log.d(TAG, "packageName=" + packageName + ",topActivityClassName=" + topActivityClassName);
        if (packageName != null && topActivityClassName != null && topActivityClassName.startsWith(packageName)) {
            Log.d(TAG, "MainActivity isRunningForeGround");
            return true;
        } else {
            Log.d(TAG, "MainActivity isRunningBackGround");
            return false;
        }
    }

    public String getTopActivityName(Context context) {
        String topActivityClassName = null;
        ActivityManager activityManager = (ActivityManager) (context.getSystemService(android.content.Context.ACTIVITY_SERVICE));
        List<ActivityManager.RunningTaskInfo> runningTaskInfos = activityManager.getRunningTasks(1);
        if (runningTaskInfos != null) {
            ComponentName f = runningTaskInfos.get(0).topActivity;
            topActivityClassName = f.getClassName();
        }
        //按下Home键盘后 topActivityClassName=com.android.launcher2.Launcher
        return topActivityClassName;
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn) {
            startActivity(new Intent(this,Main2Activity.class));
        }
    }
}

Demo下载

你可能感兴趣的:(android,home键)