最近项目中有个要求,判断当前情况属于按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)); } } }