我正在嘗試編寫一個應用程序,該應用程序在通過一段時間後回到前臺時會執行特定的操做。 有沒有一種方法能夠檢測什麼時候將應用程序發送到後臺或帶到前臺? 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(); } } }); }