我正在尝试编写一个应用程序,该应用程序在通过一段时间后回到前台时会执行特定的操做。 有没有一种方法能够检测什么时候将应用程序发送到后台或带到前台? android
我所作的是确保使用startActivityForResult
启动全部应用内活动,而后检查是否在onResume以前调用了onActivityResult。 若是不是,那就意味着咱们只是从应用程序以外的某个地方返回。 app
boolean onActivityResultCalledBeforeOnResume; @Override public void startActivity(Intent intent) { startActivityForResult(intent, 0); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); onActivityResultCalledBeforeOnResume = true; } @Override protected void onResume() { super.onResume(); if (!onActivityResultCalledBeforeOnResume) { // here, app was brought to foreground } onActivityResultCalledBeforeOnResume = false; }
编辑2:我在下面编写的内容实际上没法正常工做。 Google拒绝了一个包含对ActivityManager.getRunningTasks()的调用的应用程序。 从文档中能够明显看出,此API仅用于调试和开发目的。 我将有时间使用新的使用计时器的方案来更新下面的GitHub项目,而且很快就更新这篇文章。 ide
编辑1:我写了一篇博客文章,并建立了一个简单的GitHub存储库以使其变得很是容易。 this
公认的和评分最高的答案并非真正的最佳方法。 评分最高的答案是isApplicationBroughtToBackground()的实现,没法处理应用程序的主Activity屈服于在同一Application中定义的Activity的状况,可是它具备不一样的Java包。 我想出了一种在这种状况下可行的方法。 spa
在onPause()中调用它,它会告诉您您的应用程序是否因为另外一个应用程序启动而进入后台,或者用户按下了主页按钮。 调试
public static boolean isApplicationBroughtToBackground(final Activity activity) { ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1); // Check the top Activity against the list of Activities contained in the Application's package. if (!tasks.isEmpty()) { ComponentName topActivity = tasks.get(0).topActivity; try { PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES); for (ActivityInfo activityInfo : pi.activities) { if(topActivity.getClassName().equals(activityInfo.name)) { return false; } } } catch( PackageManager.NameNotFoundException e) { return false; // Never happens. } } return true; }
考虑使用onUserLeaveHint。 仅当您的应用进入后台时才会调用此方法。 onPause将处理一些特殊状况,由于能够出于其余缘由调用它; 例如,若是用户在您的应用程序中打开了另外一个活动(例如设置页面),则即便主活动的onPause方法仍在您的应用程序中,也会被调用; 当您能够简单地使用onUserLeaveHint回调来执行您要查询的操做时,跟踪发生的状况将致使错误。 rest
调用UserLeaveHint时,能够将boolean inBackground标志设置为true。 调用onResume时,仅当设置了inBackground标志时才假定您回到了前台。 这是由于,若是用户只是在您的设置菜单中而且从未离开过该应用程序,则onResume也会在您的主要活动中被调用。 code
请记住,若是用户在设置屏幕中单击主页按钮,则将在您的设置活动中调用onUserLeaveHint,而当他们返回时,将在您的设置活动中调用onResume。 若是您的主要活动中仅包含此检测代码,则将错过此用例。 要在全部活动中都使用此代码而不重复代码,请使用抽象的活动类来扩展Activity,而后将通用代码放入其中。 而后,您拥有的每一个活动均可以扩展此抽象活动。 继承
例如: 事件
public abstract AbstractActivity extends Activity { private static boolean inBackground = false; @Override public void onResume() { if (inBackground) { // You just came from the background inBackground = false; } else { // You just returned from another activity within your own app } } @Override public void onUserLeaveHint() { inBackground = true; } } public abstract MainActivity extends AbstractActivity { ... } public abstract SettingsActivity extends AbstractActivity { ... }
这是我设法解决此问题的方法。 它的前提是,在活动转换之间使用时间参考极可能会提供足够的证据来证实某个应用程序是否已经“后台”。
首先,我使用了一个android.app.Application实例(咱们将其称为MyApplication),该实例具备一个Timer,TimerTask,一个常数,表示从一个活动到另外一个活动的过渡能够合理花费的最大毫秒数(我去了(值为2s)和一个布尔值,指示应用程序是否在“后台”:
public class MyApplication extends Application { private Timer mActivityTransitionTimer; private TimerTask mActivityTransitionTimerTask; public boolean wasInBackground; private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000; ...
该应用程序还提供了两种启动和中止计时器/任务的方法:
public void startActivityTransitionTimer() { this.mActivityTransitionTimer = new Timer(); this.mActivityTransitionTimerTask = new TimerTask() { public void run() { MyApplication.this.wasInBackground = true; } }; this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask, MAX_ACTIVITY_TRANSITION_TIME_MS); } public void stopActivityTransitionTimer() { if (this.mActivityTransitionTimerTask != null) { this.mActivityTransitionTimerTask.cancel(); } if (this.mActivityTransitionTimer != null) { this.mActivityTransitionTimer.cancel(); } this.wasInBackground = false; }
该解决方案的最后一部分是从全部活动的onResume()和onPause()事件,或者最好在一个基本Activity中添加对每一个方法的调用,您的全部具体Activity都将继承自该基本Activity:
@Override public void onResume() { super.onResume(); MyApplication myApp = (MyApplication)this.getApplication(); if (myApp.wasInBackground) { //Do specific came-here-from-background code } myApp.stopActivityTransitionTimer(); } @Override public void onPause() { super.onPause(); ((MyApplication)this.getApplication()).startActivityTransitionTimer(); }
所以,在用户只是在您的应用程序的活动之间导航的状况下,离开活动的onPause()启动计时器,可是几乎当即输入的新活动会在达到最大过渡时间以前取消计时器。 所以wasInBackground将为false 。
另外一方面,当活动从启动器进入前台,设备唤醒,结束电话等时,颇有可能在此事件以前执行了计时器任务,所以wasInBackground设置为true 。
在您的应用程序中,添加回调并以以下方式检查root活动:
@Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityStopped(Activity activity) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { if (activity.isTaskRoot() && !(activity instanceof YourSplashScreenActivity)) { Log.e(YourApp.TAG, "Reload defaults on restoring from background."); loadDefaults(); } } }); }