如何检测Android应用程序何时进入后台并返回前台

时间:2010-12-10 23:22:41

标签: android background foreground

我正在尝试编写一个应用程序,该应用程序在经过一段时间后返回到前台时会执行某些特定操作。有没有办法检测应用程序何时发送到后台或带到前台?

43 个答案:

答案 0 :(得分:173)

以下是我设法解决这个问题的方法。它的前提是在活动转换之间使用时间参考很可能提供足够的证据证明应用程序已被“背景化”。

首先,我使用了一个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()事件中添加对这些方法中的每一个的调用,或者最好是在所有具体活动继承的基本活动中添加: / p>

@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

另一方面,当一个Activity从Launcher到达前台时,设备唤醒,结束通话等,很可能是在此事件之前执行的计时器任务,因此 wasInBackground 设置为 true

答案 1 :(得分:130)

修改:新架构组件带来了一些有希望的东西:ProcessLifecycleOwner,请参阅@vokilam's answer

根据Google I/O talk

的实际解决方案
class YourApplication : Application() {

  override fun onCreate() {
    super.onCreate()
    registerActivityLifecycleCallbacks(AppLifecycleTracker())
  }

}


class AppLifecycleTracker : Application.ActivityLifecycleCallbacks  {

  private var numStarted = 0

  override fun onActivityStarted(activity: Activity?) {
    if (numStarted == 0) {
      // app went to foreground
    }
    numStarted++
  }

  override fun onActivityStopped(activity: Activity?) {
    numStarted--
    if (numStarted == 0) {
      // app went to background
    }
  }

}

是。我知道很难相信这个简单的解决方案是有效的,因为我们在这里有很多奇怪的解决方案。

但是有希望。

答案 2 :(得分:87)

当应用程序进入后台并再次进入前台时,将调用onPause()onResume()方法。但是,当应用程序第一次启动并且在它被杀死之前,它们也会被调用。您可以在 Activity 中阅读更多内容。

在后台或前台获取应用程序状态没有任何直接方法,但即使我遇到此问题,也找到了onWindowFocusChangedonStop的解决方案。

有关详情,请点击此处 Android: Solution to detect when an Android app goes to the background and come back to the foreground without getRunningTasks or getRunningAppProcesses

答案 3 :(得分:85)

ProcessLifecycleOwner似乎也是一个很有前途的解决方案。

  

当第一个活动在这些事件中移动时,ProcessLifecycleOwner将调度ON_STARTON_RESUME个事件。 ON_PAUSEON_STOP,事件将在最后一项活动通过后以延迟发送。此延迟足够长,以保证ProcessLifecycleOwner在活动因配置更改而被销毁和重新创建时不会发送任何事件。

实现可以像

一样简单
public class AppLifecycleListener implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onMoveToForeground() {
        // app moved to foreground
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onMoveToBackground() {
       // app moved to background
    }
}

// register observer
ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppLifecycleListener());

根据源代码,当前延迟值为700ms

同样使用此功能需要dependencies

implementation "android.arch.lifecycle:extensions:1.1.1" 
annotationProcessor "android.arch.lifecycle:compiler:1.1.1"

答案 4 :(得分:64)

根据MartínMarconcinis的回答(谢谢!)我终于找到了一个可靠(而且非常简单)的解决方案。

public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

    private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName();
    private static boolean isInBackground = false;

    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {
    }

    @Override
    public void onActivityStarted(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {

        if(isInBackground){
            Log.d(TAG, "app went to foreground");
            isInBackground = false;
        }
    }

    @Override
    public void onActivityPaused(Activity activity) {
    }

    @Override
    public void onActivityStopped(Activity activity) {
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {
    }

    @Override
    public void onLowMemory() {
    }

    @Override
    public void onTrimMemory(int i) {
        if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){
            Log.d(TAG, "app went to background");
            isInBackground = true;
        }
    }
}

然后将其添加到Application类的onCreate()

public class MyApp extends android.app.Application {

    @Override
    public void onCreate() {
        super.onCreate();

        ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
        registerActivityLifecycleCallbacks(handler);
        registerComponentCallbacks(handler);

    }

}

答案 5 :(得分:59)

我们使用这种方法。它看起来太简单了,但它在我们的应用程序中经过了充分测试,实际上在所有情况下工作都非常出色,包括通过“主页”按钮,“返回”按钮或屏幕锁定后进入主屏幕。试一试。

想法是,当处于前台时,Android总是在停止前一个活动之前启动新活动。这不是保证,但它是如何工作的。 BTW,Flurry似乎使用相同的逻辑(只是一个猜测,我没有检查,但它挂钩相同的事件)。

public abstract class BaseActivity extends Activity {

    private static int sessionDepth = 0;

    @Override
    protected void onStart() {
        super.onStart();       
        sessionDepth++;
        if(sessionDepth == 1){
        //app came to foreground;
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (sessionDepth > 0)
            sessionDepth--;
        if (sessionDepth == 0) {
            // app went to background
        }
    }

}

编辑:根据评论,我们也在更高版本的代码中转移到onStart()。此外,我正在添加超级调用,这些调用在我的初始帖子中缺失,因为这更像是一个概念而非工作代码。

答案 6 :(得分:55)

如果您的应用包含多个活动和/或堆叠的活动(如标签栏小部件),则覆盖onPause()和onResume()将无效。即,在开始新活动时,当前活动将在创建新活动之前暂停。完成(使用“后退”按钮)活动时也是如此。

我发现了两种看似按需运作的方法。

第一个需要GET_TASKS权限,并且包含一个简单的方法,通过比较包名称来检查设备上的最高运行活动是否属于应用程序:

private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(context.getPackageName())) {
            return true;
        }
    }

    return false;
}

这种方法在Droid-Fu(现称为Ignition)框架中找到。

我实现自己的第二种方法不需要GET_TASKS权限,这很好。相反,实施起来要复杂一些。

在MainApplication类中,您有一个跟踪应用程序中正在运行的活动数量的变量。在每个活动的onResume()中增加变量,在onPause()中减少它。

当运行活动的数量达到0时,如果满足以下条件,则将应用程序置于后台:

  • 暂停的活动未完成(使用“后退”按钮)。这可以通过使用方法activity.isFinishing()
  • 来完成
  • 未启动新活动(相同的包名称)。您可以覆盖startActivity()方法来设置一个指示此变量的变量,然后在onPostResume()中重置它,这是创建/恢复活动时要运行的最后一个方法。

如果您可以检测到应用程序已退回到后台,则很容易检测到它何时返回到前台。

答案 7 :(得分:33)

创建扩展wordSorting wordElement[num_of_elements]; 。然后在其中我们可以使用其覆盖方法Application

要检测应用程序是否转到后台,我们将使用:

onTrimMemory()

答案 8 :(得分:17)

考虑使用onUserLeaveHint。这只会在您的应用进入后台时调用。 onPause将有角落案件要处理,因为它可以出于其他原因被调用;例如,如果用户在您的应用中打开了另一项活动(例如您的设置页面),即使它们仍在您的应用中,您的主要活动的onPause方法也会被调用;跟踪进入的内容会导致错误,而只需使用onUserLeaveHint回调来执行您所要求的操作。

调用UserLeaveHint时,可以将boolean inBackground标志设置为true。当调用onResume时,如果设置了inBackground标志,则只假设您回到前台。这是因为如果用户只是在您的设置菜单中并且从未离开过该应用,则还会在您的主要活动上调用onResume。

请记住,如果用户在设置屏幕中点击主页按钮,则会在您的设置活动中调用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 {
    ...
}

答案 9 :(得分:13)

ActivityLifecycleCallbacks可能会引起人们的兴趣,但没有详细记录。

但是,如果你打电话给registerActivityLifecycleCallbacks(),你应该能够在创建,销毁等活动时获得回调。你可以为活动打电话getComponentName()。

答案 10 :(得分:9)

android.arch.lifecycle 包提供了类和接口,可让您构建可识别生命周期的组件

您的应用程序应实现LifecycleObserver接口:

public class MyApplication extends Application implements LifecycleObserver {

    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private void onAppBackgrounded() {
        Log.d("MyApp", "App in background");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onAppForegrounded() {
        Log.d("MyApp", "App in foreground");
    }
}

为此,您需要将此依赖项添加到build.gradle文件中:

dependencies {
    implementation "android.arch.lifecycle:extensions:1.1.1"
}

按照Google的建议,您应尽量减少在活动的生命周期方法中执行的代码:

  

一个常见的模式是实施依赖者的行为   活动和片段的生命周期方法中的组件。   但是,这种模式导致代码的组织不善,并导致   错误的扩散。通过使用生命周期感知的组件,您可以   可以将依赖组件的代码移出生命周期方法   以及组件本身。

您可以在此处了解更多信息: https://developer.android.com/topic/libraries/architecture/lifecycle

答案 11 :(得分:8)

在您的应用程序中添加回调并以下列方式检查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();
            }
        }
    });
}

答案 12 :(得分:6)

我在Github上创建了一个项目app-foreground-background-listen

为应用程序中的所有活动创建BaseActivity。

public class BaseActivity extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

    public static boolean isAppInFg = false;
    public static boolean isScrInFg = false;
    public static boolean isChangeScrFg = false;

    @Override
    protected void onStart() {
        if (!isAppInFg) {
            isAppInFg = true;
            isChangeScrFg = false;
            onAppStart();
        }
        else {
            isChangeScrFg = true;
        }
        isScrInFg = true;

        super.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();

        if (!isScrInFg || !isChangeScrFg) {
            isAppInFg = false;
            onAppPause();
        }
        isScrInFg = false;
    }

    public void onAppStart() {

        // Remove this toast
        Toast.makeText(getApplicationContext(), "App in foreground",    Toast.LENGTH_LONG).show();

        // Your code
    }

    public void onAppPause() {

        // Remove this toast
        Toast.makeText(getApplicationContext(), "App in background",  Toast.LENGTH_LONG).show();

        // Your code
    }
}

现在使用此BaseActivity作为所有Activity的超类,如MainActivity扩展BaseActivity,并在启动应用程序时调用onAppStart,当应用程序从任何屏幕进入后台时,将调用onAppPause()。

答案 13 :(得分:6)

ProcessLifecycleOwner

非常简单

添加这些依赖关系

implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"

Kotlin

class ForegroundBackgroundListener : LifecycleObserver {


    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun startSomething() {
        Log.v("ProcessLog", "APP IS ON FOREGROUND")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stopSomething() {
        Log.v("ProcessLog", "APP IS IN BACKGROUND")
    }
}

然后在你的基础活动中:

override fun onCreate() {
        super.onCreate()

        ProcessLifecycleOwner.get()
                .lifecycle
                .addObserver(
                        ForegroundBackgroundListener()
                                .also { appObserver = it })
    }

请参阅我关于此主题的文章: https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48

答案 14 :(得分:5)

您可以使用ProcessLifecycleOwner为其附加生命周期观察器。

  public class ForegroundLifecycleObserver implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onAppCreated() {
        Timber.d("onAppCreated() called");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onAppStarted() {
        Timber.d("onAppStarted() called");
    }

    @OnLifecycleEvent(Event.ON_RESUME)
    public void onAppResumed() {
        Timber.d("onAppResumed() called");
    }

    @OnLifecycleEvent(Event.ON_PAUSE)
    public void onAppPaused() {
        Timber.d("onAppPaused() called");
    }

    @OnLifecycleEvent(Event.ON_STOP)
    public void onAppStopped() {
        Timber.d("onAppStopped() called");
    }
}

然后在Application类的onCreate()上将其称为:

ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());

通过此操作,您将能够捕获应用程序在后台运行时发生的ON_PAUSEON_STOP事件。

答案 15 :(得分:3)

编辑2:我在下面写的内容实际上不起作用。谷歌拒绝了一个包含对ActivityManager.getRunningTasks()的调用的应用程序。从the documentation可以看出,此API仅用于调试和开发目的。一旦我有时间用一个使用计时器的新方案更新下面的GitHub项目,我将立即更新这篇文章。

编辑1:我写了一个blog post并创建了a simple GitHub repository来简化这一过程。

接受且评价最高的答案都不是最好的方法。最受好评的答案的isApplicationBroughtToBackground()实现不能处理Application的主Activity对同一Application中定义的Activity产生影响的情况,但它有一个不同的Java包。我提出了一种方法,可以在这种情况下使用。

在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;
}

答案 16 :(得分:3)

I found a good method to detect application whether enter foreground or background. Here is my code. Hope this help you.

/**
 * Custom Application which can detect application state of whether it enter
 * background or enter foreground.
 *
 * @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html
 */
 public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks {

public static final int STATE_UNKNOWN = 0x00;
public static final int STATE_CREATED = 0x01;
public static final int STATE_STARTED = 0x02;
public static final int STATE_RESUMED = 0x03;
public static final int STATE_PAUSED = 0x04;
public static final int STATE_STOPPED = 0x05;
public static final int STATE_DESTROYED = 0x06;

private static final int FLAG_STATE_FOREGROUND = -1;
private static final int FLAG_STATE_BACKGROUND = -2;

private int mCurrentState = STATE_UNKNOWN;
private int mStateFlag = FLAG_STATE_BACKGROUND;

@Override
public void onCreate() {
    super.onCreate();
    mCurrentState = STATE_UNKNOWN;
    registerActivityLifecycleCallbacks(this);
}

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    // mCurrentState = STATE_CREATED;
}

@Override
public void onActivityStarted(Activity activity) {
    if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) {
        if (mStateFlag == FLAG_STATE_BACKGROUND) {
            applicationWillEnterForeground();
            mStateFlag = FLAG_STATE_FOREGROUND;
        }
    }
    mCurrentState = STATE_STARTED;

}

@Override
public void onActivityResumed(Activity activity) {
    mCurrentState = STATE_RESUMED;

}

@Override
public void onActivityPaused(Activity activity) {
    mCurrentState = STATE_PAUSED;

}

@Override
public void onActivityStopped(Activity activity) {
    mCurrentState = STATE_STOPPED;

}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

}

@Override
public void onActivityDestroyed(Activity activity) {
    mCurrentState = STATE_DESTROYED;
}

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) {
        if (mStateFlag == FLAG_STATE_FOREGROUND) {
            applicationDidEnterBackground();
            mStateFlag = FLAG_STATE_BACKGROUND;
        }
    }else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) {
        if (mStateFlag == FLAG_STATE_FOREGROUND) {
            applicationDidDestroyed();
            mStateFlag = FLAG_STATE_BACKGROUND;
        }
    }
}

/**
 * The method be called when the application been destroyed. But when the
 * device screen off,this method will not invoked.
 */
protected abstract void applicationDidDestroyed();

/**
 * The method be called when the application enter background. But when the
 * device screen off,this method will not invoked.
 */
protected abstract void applicationDidEnterBackground();

/**
 * The method be called when the application enter foreground.
 */
protected abstract void applicationWillEnterForeground();

}

答案 17 :(得分:3)

您可以使用:

  

protected void onRestart()

在新启动和重新启动之间有所不同。

enter image description here

答案 18 :(得分:2)

这里的正确答案

创建名为MyApp的类,如下所示:

public class MyApp implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

    private Context context;
    public void setContext(Context context)
    {
        this.context = context;
    }

    private boolean isInBackground = false;

    @Override
    public void onTrimMemory(final int level) {
        if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {


            isInBackground = true;
            Log.d("status = ","we are out");
        }
    }


    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {

        if(isInBackground){

            isInBackground = false;
            Log.d("status = ","we are in");
        }

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {

    }

    @Override
    public void onLowMemory() {

    }
}

然后,在您想要的任何地方(在应用中推出更好的第一个活动),添加以下代码:

MyApp myApp = new MyApp();
registerComponentCallbacks(myApp);
getApplication().registerActivityLifecycleCallbacks(myApp);

完成!现在当应用程序在后台时,我们得到日志status : we are out 当我们进入app时,我们得到log status : we are out

答案 19 :(得分:2)

没有简单的生命周期方法可以告诉您整个应用程序何时变为后台/前景。

我已经用简单的方法做到了。请按照以下说明检测应用程序的背景/前景阶段。

有一些解决方法,这是可能的。在这里, ActivityLifecycleCallbacks 可以解决。让我逐步讲解。

  1. 首先,创建一个扩展 android.app.Application 并实现 ActivityLifecycleCallbacks 接口的类。在Application.onCreate()中,注册回调。

    public class App extends Application implements 
        Application.ActivityLifecycleCallbacks {
    
        @Override
        public void onCreate() {
            super.onCreate();
            registerActivityLifecycleCallbacks(this);
        }
    }
    
  2. 如下所示在清单中注册“ App”类,<application android:name=".App"

  3. 当应用程序处于前台状态时,至少有一个处于启动状态的活动,而当应用程序处于后台时,则不会处于启动状态。

    在“ App”类中声明以下2个变量。

    private int activityReferences = 0;
    private boolean isActivityChangingConfigurations = false;
    

    activityReferences会将活动计数保持在已开始状态。 isActivityChangingConfigurations是一个标志,用于指示当前的活动是否正在像方向开关一样进行配置更改。

  4. 使用以下代码,您可以检测该应用程序是否成为前台。

    @Override
    public void onActivityStarted(Activity activity) {
        if (++activityReferences == 1 && !isActivityChangingConfigurations) {
            // App enters foreground
        }
    }
    
  5. 这是检测应用程序是否进入后台的方法。

    @Override
    public void onActivityStopped(Activity activity) {
        isActivityChangingConfigurations = activity.isChangingConfigurations();
        if (--activityReferences == 0 && !isActivityChangingConfigurations) {
            // App enters background
        }
    }
    

工作方式:

这是按顺序调用Lifecycle方法的一种技巧。让我来演示一个场景。

假定用户启动了该应用程序,并且启动了活动启动器A。生命周期调用将是

  

A.onCreate()

     

A.onStart()(++ activityReferences == 1)(应用进入前台)

     

A.onResume()

现在,活动A启动活动B。

  

A.onPause()

     

B.onCreate()

     

B.onStart()(++ activityReferences == 2)

     

B.onResume()

     

A.onStop()(--activityReferences == 1)

然后用户从活动B导航回来,

  

B.onPause()

     

A.onStart()(++ activityReferences == 2)

     

A.onResume()

     

B.onStop()(--activityReferences == 1)

     

B.onDestroy()

然后用户按下“主页”按钮,

  

A.onPause()

     

A.onStop()(--activityReferences == 0)(应用进入后台)

在这种情况下,如果用户从活动B中按下“主页”按钮而不是“后退”按钮,则仍然是相同的,activityReferences将为0。因此,我们可以检测到App进入背景。

那么isActivityChangingConfigurations的作用是什么?在上述情况下,假设活动B改变了方向。回调顺序为

  

B.onPause()

     

B.onStop()(--activityReferences == 0)(应用进入背景?)

     

B.onDestroy()

     

B.onCreate()

     

B.onStart()(++ activityReferences == 1)(应用进入前台?)

     

B.onResume()

这就是为什么我们要另外检查isActivityChangingConfigurations的原因,以避免在活动进行配置更改时出现这种情况。

答案 20 :(得分:1)

由于我没有找到任何方法,该方法也可以在不检查时间戳的情况下处理旋转,因此我想我也分享了我们现在在应用程序中的处理方式。 此答案https://stackoverflow.com/a/42679191/5119746的唯一补充是,我们还考虑了方向。

class MyApplication : Application(), Application.ActivityLifecycleCallbacks {

   // Members

   private var mAppIsInBackground = false
   private var mCurrentOrientation: Int? = null
   private var mOrientationWasChanged = false
   private var mResumed = 0
   private var mPaused = 0

然后,对于回调,我们首先要恢复简历:

   // ActivityLifecycleCallbacks

   override fun onActivityResumed(activity: Activity?) {

      mResumed++

      if (mAppIsInBackground) {

         // !!! App came from background !!! Insert code

         mAppIsInBackground = false
      }
      mOrientationWasChanged = false
    }

并且onActivityStopped:

   override fun onActivityStopped(activity: Activity?) {

       if (mResumed == mPaused && !mOrientationWasChanged) {

       // !!! App moved to background !!! Insert code

        mAppIsInBackground = true
    }

然后,添加了以下内容:检查方向变化:

   override fun onConfigurationChanged(newConfig: Configuration) {

       if (newConfig.orientation != mCurrentOrientation) {
           mCurrentOrientation = newConfig.orientation
           mOrientationWasChanged = true
       }
       super.onConfigurationChanged(newConfig)
   }

就是这样。希望这对某人有帮助:)

答案 21 :(得分:1)

您可以在ActivityLifecycleCallbacksComponentCallbacks2之类的帮助下轻松实现此目标。

创建一个实现上述接口的类AppLifeCycleHandler

package com.sample.app;

import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks2;
import android.content.res.Configuration;
import android.os.Bundle;

/**
 * Created by Naveen on 17/04/18
 */
public class AppLifeCycleHandler
    implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

  AppLifeCycleCallback appLifeCycleCallback;

  boolean appInForeground;

  public AppLifeCycleHandler(AppLifeCycleCallback appLifeCycleCallback) {
    this.appLifeCycleCallback = appLifeCycleCallback;
  }

  @Override
  public void onActivityResumed(Activity activity) {
    if (!appInForeground) {
      appInForeground = true;
      appLifeCycleCallback.onAppForeground();
    }
  }

  @Override
  public void onTrimMemory(int i) {
    if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
      appInForeground = false;
      appLifeCycleCallback.onAppBackground();
    }
  }

  @Override
  public void onActivityCreated(Activity activity, Bundle bundle) {

  }

  @Override
  public void onActivityStarted(Activity activity) {

  }

  @Override
  public void onActivityPaused(Activity activity) {

  }

  @Override
  public void onActivityStopped(Activity activity) {

  }

  @Override
  public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

  }

  @Override
  public void onActivityDestroyed(Activity activity) {

  }

  @Override
  public void onConfigurationChanged(Configuration configuration) {

  }

  @Override
  public void onLowMemory() {

  }

  interface AppLifeCycleCallback {

    void onAppBackground();

    void onAppForeground();
  }
}

在您的类中扩展Application实现AppLifeCycleCallback以获取应用在前台和后台之间切换时的回调。像下面的东西。

public class BaseApplication extends Application implements AppLifeCycleHandler.AppLifeCycleCallback{

    @Override
    public void onCreate() {
        super.onCreate();
        AppLifeCycleHandler appLifeCycleHandler = new AppLifeCycleHandler(this);
        registerActivityLifecycleCallbacks(appLifeCycleHandler);
        registerComponentCallbacks(appLifeCycleHandler);
    }

    @Override
    public void onAppBackground() {
        Log.d("LifecycleEvent", "onAppBackground");
    }

    @Override
    public void onAppForeground() {
        Log.d("LifecycleEvent", "onAppForeground");
    }
}

希望这会有所帮助。

修改 作为替代方案,您现在可以使用生命周期感知架构组件。

答案 22 :(得分:1)

这是@ d60402答案的修改版本:https://stackoverflow.com/a/15573121/4747587

做那里提到的一切。但是,不是使用index.html并将其作为每项活动的父级,而是覆盖TimeoutException: Message: Timed out waiting for page load. Stacktrace: at Utils.initWebLoadingListener/< (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver@googlecode.com/components/driver-component.js:9089) at WebLoadingListener/e (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver@googlecode.com/components/driver-component.js:5145) at WebLoadingListener/< (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver@googlecode.com/components/driver-component.js:5153) at fxdriver.Timer.prototype.setTimeout/<.notify (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver@googlecode.com/components/driver-component.js:625) Base Activity,请执行以下操作:

在您的应用程序类中,添加以下行:

registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback);

onResume()包含所有活动生命周期方法,您现在可以覆盖onPausecallback

看一下这个要点:https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b

答案 23 :(得分:1)

这似乎是Android中最复杂的问题之一(截至撰写本文时)Android没有iOS等效的applicationDidEnterBackground()applicationWillEnterForeground()回调。我使用了由AppState Library汇总的@jenzz

  

[AppState]是一个基于RxJava的简单,反应式Android库,可监控应用状态变化。每次应用程序进入后台并返回前台时,它都会通知订阅者。

事实证明这正是我所需要的,特别是因为我的应用程序有多项活动,因此只需检查活动上的onStart()onStop()就不会削减它。

首先,我将这些依赖项添加到gradle:

dependencies {
    compile 'com.jenzz.appstate:appstate:3.0.1'
    compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}

然后将这些行添加到代码中的适当位置是一件简单的事情:

//Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable
Observable<AppState> appState = RxAppStateMonitor.monitor(myApplication);
//where myApplication is a subclass of android.app.Application
appState.subscribe(new Consumer<AppState>() {
    @Override
    public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception {
        switch (appState) {
            case FOREGROUND:
                Log.i("info","App entered foreground");
                break;
            case BACKGROUND:
                Log.i("info","App entered background");
                break;
        }
    }
});

根据您订阅observable的方式,您可能必须取消订阅才能避免内存泄漏。关于github page的更多信息。

答案 24 :(得分:1)

我知道它有点晚了,但我认为所有这些答案确实存在一些问题,而我在下面这样做并且完美无缺。

创建一个活动生命周期回调,如下所示:

 class ActivityLifeCycle implements ActivityLifecycleCallbacks{

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    Activity lastActivity;
    @Override
    public void onActivityResumed(Activity activity) {
        //if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when  app has been killed or started for the first time
        if (activity != null && activity == lastActivity) 
        {
            Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show();
        }

        lastActivity = activity;
    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }
}

并将其注册到您的应用程序类,如下所示:

public class MyApp extends Application {

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}

答案 25 :(得分:1)

使用 ActivityProcessLifecycleOwner(或任何类)中从后台到前台检测应用程序的示例。
当应用程序启动时,我缓存开始时间,然后在每个活动中我将检查应用程序时间以了解活动是第一次启动还是从后台启动

class MyApplication : Application(), LifecycleObserver {

    var appStartBeginTime: Long? = null

    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onMoveToForeground() {
        Log.i("TAG", "onMoveToForeground")
        appStartBeginTime = System.currentTimeMillis()
    }
}

LoginActivity

class LoginActivity : AppCompatActivity() {
    var localAppStartBeginTime: Long? = null

    ...
    
    // Detect in onResume() instead of onStart because 
    // onMoveToForeground() in MyApplication will fired before onStart 
    override fun onResume() {
        super.onResume()
        if (isOpenedFirstTimeOrFromBackground()) {
            Log.i("TAG", "open first time or from background")

            // do something: eg, call API
        } else {
            Log.i("TAG", "on in another time")
        }
    }

    private fun isOpenedFirstTimeOrFromBackground(): Boolean {
        val globalStartBeginTime = (application as MyApplication).appStartBeginTime
        if (localAppStartBeginTime != globalStartBeginTime) {
            localAppStartBeginTime = globalStartBeginTime
            return true
        }
        return false
    }
}

AndroidManifest

<manifest ...>

    <application
        android:name=".MyApplication"
        ...>
            
    </application>

</manifest>

演示 https://github.com/PhanVanLinh/AndroidDetectAppFromBackgroundToForeground

答案 26 :(得分:1)

我的解决方案受@ d60402答案的启发,并且还依赖于时间窗口,但不使用Timer

public abstract class BaseActivity extends ActionBarActivity {

  protected boolean wasInBackground = false;

  @Override
  protected void onStart() {
    super.onStart();
    wasInBackground = getApp().isInBackground;
    getApp().isInBackground = false;
    getApp().lastForegroundTransition = System.currentTimeMillis();
  }

  @Override
  protected void onStop() {
    super.onStop();
    if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition )
      getApp().isInBackground = true;
  }

  protected SingletonApplication getApp(){
    return (SingletonApplication)getApplication();
  }
}

其中SingletonApplicationApplication类的扩展名:

public class SingletonApplication extends Application {
  public boolean isInBackground = false;
  public long lastForegroundTransition = 0;
}

答案 27 :(得分:1)

我在谷歌分析EasyTracker上使用它,它运作良好。它可以扩展为使用简单的整数来执行您所寻求的操作。

public class MainApplication extends Application {

    int isAppBackgrounded = 0;

    @Override
    public void onCreate() {
        super.onCreate();
        appBackgroundedDetector();
    }

    private void appBackgroundedDetector() {
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle bundle) {

            }

            @Override
            public void onActivityStarted(Activity activity) {
                EasyTracker.getInstance(MainApplication.this).activityStart(activity);
            }

            @Override
            public void onActivityResumed(Activity activity) {
                isAppBackgrounded++;
                if (isAppBackgrounded > 0) {
                    // Do something here
                }
            }

            @Override
            public void onActivityPaused(Activity activity) {
                isAppBackgrounded--;
            }

            @Override
            public void onActivityStopped(Activity activity) {
                EasyTracker.getInstance(MainApplication.this).activityStop(activity);
            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

            }

            @Override
            public void onActivityDestroyed(Activity activity) {

            }
        });
    }
}

答案 28 :(得分:0)

我喜欢 ProcessLifecycleOwner 方法,但实际上可以跳过所有这些,因为在 ActivityonCreate() 方法中,可以轻松确定它是第一个还是后续运行:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
        /* savedInstanceState is always null on first run */
    } else {
        /* it's a subsequent run */
    }
}

答案 29 :(得分:0)

我通过实现一个BaseActivity来监视从后台导航到后台的应用导航,该后台利用了onResume,onPause和onStop活动回调的使用。这是我的实现。

override fun onResume() {
    super.onResume()
    if (AppActivityState.state == AppState.ON_LAUNCHED) {
        // We are in the first launch.
        onLaunched()
    } else {
        if (AppActivityState.state == AppState.ON_BACKGROUND) {
            // We came from background to foreground.
            AppActivityState.state = AppState.ON_FOREGROUND
            onForeground()
        } else {
            // We are just navigating through pages.
            AppActivityState.state = AppState.RESUMED
        }
    }
}

override fun onPause() {
    super.onPause()
    // If state is followed by onStop then it means we will going to background.
    AppActivityState.state = AppState.PAUSED
}

override fun onStop() {
    super.onStop()

    // App will go to background base on the 'pause' cue.
    if (AppActivityState.state == AppState.PAUSED) {
        AppActivityState.state = AppState.ON_BACKGROUND
        onBackground()
    }
}

创建BaseActivity之后,您只需要将此活动扩展到应用程序上的任何活动即可。

在这些类型的实现中,您可以准确地检测以下内容: -onBackground>应用程序将进入后台 -onForeground>应用程序将返回到前景 -onLaunch>应用刚刚打开

我希望这会对您有所帮助:)

答案 30 :(得分:0)

我们可以使用LiveData展开this solution

class AppForegroundStateLiveData : LiveData<AppForegroundStateLiveData.State>() {

    private var lifecycleListener: LifecycleObserver? = null

    override fun onActive() {
        super.onActive()
        lifecycleListener = AppLifecycleListener().also {
            ProcessLifecycleOwner.get().lifecycle.addObserver(it)
        }
    }

    override fun onInactive() {
        super.onInactive()
        lifecycleListener?.let {
            this.lifecycleListener = null
            ProcessLifecycleOwner.get().lifecycle.removeObserver(it)
        }
    }

    internal inner class AppLifecycleListener : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun onMoveToForeground() {
            value = State.FOREGROUND
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun onMoveToBackground() {
            value = State.BACKGROUND
        }
    }

    enum class State {
        FOREGROUND, BACKGROUND
    }
}

现在,我们可以订阅此LiveData并捕获所需的事件。例如:

appForegroundStateLiveData.observeForever { state ->
    when(state) {
        AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
        AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
    }
}

答案 31 :(得分:0)

您可以通过三种方式实现这一目标:

  • 单一活动架构
  • ActivityLifecycleCallback
  • LifecycleObserver和ProcessLifecycleOwner

已在here上详细撰写了一篇文章。希望对您有所帮助。

答案 32 :(得分:0)

您可以在应用程序类中简单地调用此方法

ProcessLifecycleOwner.get().getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                Log.e(TAG, "onStateChanged: " + event.toString());
            }
        });

Lifecycle.Event将仅返回应用程序的状态

ON_CREATE
ON_START
ON_RESUME
ON_PAUSE
ON_STOP
ON_DESTROY
ON_ANY

当应用程序进入后台时,它将返回ON_PAUSE和ON_STOP 并在应用程序进入前台时返回ON_START和ON_RESUME

答案 33 :(得分:0)

通过使用以下代码,我可以获得我的应用前景或背景状态。

有关其有效的详细信息,请点击here

import android.content.ComponentCallbacks2;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

private Context context;
private Toast toast;

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

private void showToast(String message) {
    //If toast is already showing cancel it
    if (toast != null) {
        toast.cancel();
    }

    toast = Toast.makeText(context, message, Toast.LENGTH_SHORT);
    toast.show();
}

@Override
protected void onStart() {
    super.onStart();
    showToast("App In Foreground");
}

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        showToast("App In Background");
    }
  }
}

答案 34 :(得分:0)

这个解决方案怎么样

public class BaseActivity extends Activity
{

    static String currentAct = "";

    @Override
    protected void onStart()
    {
        super.onStart();

        if (currentAct.equals(""))
            Toast.makeText(this, "Start", Toast.LENGTH_LONG).show();

        currentAct = getLocalClassName();
    }

    @Override
    protected void onStop()
    {
        super.onStop();

        if (currentAct.equals(getLocalClassName()))
        {
            currentAct = "";
            Toast.makeText(this, "Stop", Toast.LENGTH_LONG).show();
        }
    }
}

所有活动都需要扩展BaseActivity。

当一个活动调用另一个(A-> B)时,currentAct不等于getLocalClassName(),因为第二个活动(B)的onStart()在第一个(A)的onStop()之前被调用({ {3}})。

当用户按下主页按钮或在应用程序之间切换时,只需调用onStop(),然后currentAct等于getLocalClassName()。

答案 35 :(得分:0)

我的应用程序需要在从后台返回后“重新启动” - 根据客户请求显示一系列活动。在广泛搜索了如何管理背景/前景转换(iOS和Android之间的处理方式非常不同)后,我提出了这个问题。在这里找到了非常有用的帮助,特别是从投票最多的答案和标记为正确的答案。但是,当您考虑UX时,只需重新实例化根活动,应用程序进入前台的时候看起来太烦人了。根据Youtube和Twitter应用功能,对我有用的解决方案和我认为最充分的解决方案是将@GirishNair和@ d60402的答案结合起来:在应用程序修剪内存时调用计时器,如下所示:

@Override
public void onTrimMemory(int level) {
    if (stateOfLifeCycle.equals("Stop")) {
        startActivityTransitionTimer();
    }

    super.onTrimMemory(level);
}

我的计时器限制设置为30秒 - 我正在考虑增加一点。

private final long MAX_ACTIVITY_TRANSITION_TIME = 30000;

当应用程序进入前台,重新启动或应用程序被破坏时,请调用该方法取消计时器。

在App扩展程序上:

@Override
public void onActivityCreated(Activity activity, Bundle arg1) {
    stopActivityTransitionTimer();
    stateOfLifeCycle = "Create";
}

@Override
public void onActivityDestroyed(Activity activity) {
    stopActivityTransitionTimer();
    stateOfLifeCycle = "Destroy";
}

关于活动(最好是基础活动,由其他活动继承):

@Override
protected void onStart() {
    super.onStart();
    if (App.wasInBackground) {
        stopActivityTransitionTimer();
    }
}

在我的情况下,当app在最长时间之后进入前景时,会创建一个新任务,因此在应用程序扩展类中的onActivityCreated()或onActivityDestroyed()上调用stopActivityTransitionTimer() - 不需要调用方法在一项活动中。 希望它有所帮助。

答案 36 :(得分:0)

这是我的解决方案。只需在主Application类中注册此ActivityLifecycleCallbacks。在评论中,我提到了用户配置文件活动边缘案例。该活动只是一个透明边缘。

/**
 * This class used Activity lifecycle callbacks to determine when the application goes to the
 * background as well as when it is brought to the foreground.
 */
public class Foreground implements Application.ActivityLifecycleCallbacks
{
    /**
     * How long to wait before checking onStart()/onStop() count to determine if the app has been
     * backgrounded.
     */
    public static final long BACKGROUND_CHECK_DELAY_MS = 500;

    private static Foreground sInstance;

    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
    private boolean mIsForeground = false;
    private int mCount;

    public static void init(final Application application)
    {
        if (sInstance == null)
        {
            sInstance = new Foreground();
            application.registerActivityLifecycleCallbacks(sInstance);
        }
    }

    public static Foreground getInstance()
    {
        return sInstance;
    }

    public boolean isForeground()
    {
        return mIsForeground;
    }

    public boolean isBackground()
    {
        return !mIsForeground;
    }

    @Override
    public void onActivityStarted(final Activity activity)
    {
        mCount++;

        // Remove posted Runnables so any Meteor disconnect is cancelled if the user comes back to
        // the app before it runs.
        mMainThreadHandler.removeCallbacksAndMessages(null);

        if (!mIsForeground)
        {
            mIsForeground = true;
        }
    }

    @Override
    public void onActivityStopped(final Activity activity)
    {
        mCount--;

        // A transparent Activity like community user profile won't stop the Activity that launched
        // it. If you launch another Activity from the user profile or hit the Android home button,
        // there are two onStops(). One for the user profile and one for its parent. Remove any
        // posted Runnables so we don't get two session ended events.
        mMainThreadHandler.removeCallbacksAndMessages(null);
        mMainThreadHandler.postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                if (mCount == 0)
                {
                    mIsForeground = false;
                }
            }
        }, BACKGROUND_CHECK_DELAY_MS);
    }

    @Override
    public void onActivityCreated(final Activity activity, final Bundle savedInstanceState)
    {

    }

    @Override
    public void onActivityResumed(final Activity activity)
    {

    }

    @Override
    public void onActivityPaused(final Activity activity)
    {

    }

    @Override
    public void onActivitySaveInstanceState(final Activity activity, final Bundle outState)
    {

    }

    @Override
    public void onActivityDestroyed(final Activity activity)
    {

    }
}

答案 37 :(得分:0)

这是我的解决方案https://github.com/doridori/AndroidUtils/blob/master/App/src/main/java/com/doridori/lib/app/ActivityCounter.java

基本上涉及使用计时器计算所有活动的生命周期方法,以捕获前景中当前没有活动但是应用程序(即轮换)的情况

答案 38 :(得分:0)

我所做的是确保使用startActivityForResult启动所有应用内活动,然后检查onResume之前是否调用了onActivityResult。如果它不是,那就意味着我们只是从应用程序之外的某个地方返回。

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;
}

答案 39 :(得分:0)

这些答案似乎不正确。当另一个活动开始和结束时,也会调用这些方法。你可以做的是保持一个全局标志(是的,全局变量是坏:)并在每次开始一个新活动时将其设置为true。在每个活动的onCreate中将其设置为false。然后,在onPause中检查此标志。如果它是假的,你的应用程序将进入后台,或者它正在被杀死。

答案 40 :(得分:-1)

我正在使用此解决方案: http://nathanael.hevenet.com/android-dev-detecting-when-your-app-is-in-the-background-across-activities/

简而言之 - 构建一个专门的服务,每个活动都会报告每个生命周期事件,并且此服务会获取有关应用状态的信息。

非常像@ oldschool4664解决方案,但在我看来更干净

答案 41 :(得分:-1)

最简单的方法(无需其他库)

科特琳:

var handler = Handler()
var isAppInBackground = true

override fun onStop() {
    super.onStop()
    handler.postDelayed({ isAppInBackground = true },2000)
}
override fun onDestroy() {
    super.onDestroy()
    handler.removeCallbacksAndMessages(null)
    isAppInBackground = false
}

Java:

Handler handler = new Handler();
boolean isAppInBackground = true;

@Override
public void onStop() {
    super.onStop();
    handler.postDelayed(() -> { isAppInBackground = true; },2000);
}
@Override
public void onDestroy() {
    super.onDestroy();
    handler.removeCallbacksAndMessages(null);
    isAppInBackground = false;
}

答案 42 :(得分:-3)

主要问题是,当您从后台启动活动时,必须获取特定行为。如果你覆盖onPause()和onResume()方法,你将得到一个接近的答案,但不是解决方案。问题是即使您没有最小化应用程序,也会调用onPause()和onResume()方法,可以在启动活动时调用它们,然后按后退按钮返回到您的活动。 要消除这个问题并确切知道您的应用程序何时来自后台,您必须获得正在运行的流程并与您的流程进行比较:

private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(getPackageName())) {
            return true;
        }
    }
    return false;
}

现在你必须声明一个布尔变量:

public boolean wasPaused = false;

并询问您的活动何时到达背景:

@Override
public void onPause(){
    super.onPause();
    if(isApplicationBroughtToBackground())
        wasPaused = true;
}

现在,当您的活动再次进入屏幕时,请询问onResume()方法:

@Override
public void onResume(){
    super.onResume();
    if(wasPaused){
        lockScreen(true);
    }
    wasPaused = false;
}

就是这样。现在,当您的活动进入后台,稍后用户将其带到前台时,将出现锁定屏幕。

如果要对应用的任何活动重复此行为,则必须创建活动(可能是BaseActivity),放置此方法,并且所有活动都必须从BaseActivity继承。

我希望这对你有所帮助。

问候!