我试图写一个应用程序,做一些具体的时候,它被带回前台后一段时间。是否有一种方法可以检测应用程序是被发送到后台还是被带到前台?


当前回答

我们用这个方法。它看起来太简单了,但它在我们的应用程序中经过了良好的测试,实际上在所有情况下都运行得非常好,包括通过“home”按钮进入主屏幕,通过“返回”按钮,或在屏幕锁定后返回主屏幕。试一试。

想法是,当在前景,Android总是开始新的活动之前停止前一个。这并不能保证,但这就是它的工作原理。顺便说一句,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()在以后的版本的代码。此外,我还添加了超级调用,这是我最初的文章中所没有的,因为这更像是一个概念,而不是一个工作代码。

其他回答

2021年11月更新

实际设置如下

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())
    }
}

class AppLifecycleListener : DefaultLifecycleObserver {

    override fun onStart(owner: LifecycleOwner) { // app moved to foreground
    }

    override fun onStop(owner: LifecycleOwner) { // app moved to background
    }
}

依赖关系

implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common:$lifecycle_version"

原来的答案

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

ProcessLifecycleOwner将分派ON_START, ON_RESUME事件,当第一个活动通过这些事件时。ON_PAUSE, ON_STOP,事件将在最后一个活动通过它们后延迟分派。这个延迟足够长,可以保证ProcessLifecycleOwner在由于配置更改而销毁和重新创建活动时不会发送任何事件。

实现可以简单到

class AppLifecycleListener : LifecycleObserver {

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

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

// register observer
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())

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

使用此特性还需要依赖项:

implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"

没有直接的生命周期方法来告诉你整个应用程序何时进入后台或前台。

我用简单的方法做了这件事。按照下面的说明检测应用程序后台/前台阶段。

只要有一点变通办法,这是可能的。在这里,ActivityLifecycleCallbacks可以救场。让我一步一步来。

First, create a class that extends the android.app.Application and implements the ActivityLifecycleCallbacks interface. In the Application.onCreate(), register the callback. public class App extends Application implements Application.ActivityLifecycleCallbacks { @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(this); } } Register the “App” class in the Manifest as below, <application android:name=".App". There will be at least one Activity in the started state when the app is in the foreground and there will be no Activity in the started state when the app is in the background. Declare 2 variables as below in the “App” class. private int activityReferences = 0; private boolean isActivityChangingConfigurations = false; activityReferences will keep the count of number of activities in the started state. isActivityChangingConfigurations is a flag to indicate if the current Activity is going through configuration change like an orientation switch. Using the following code you can detect if the App comes foreground. @Override public void onActivityStarted(Activity activity) { if (++activityReferences == 1 && !isActivityChangingConfigurations) { // App enters foreground } } This is how to detect if the App goes background. @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 ()

然后用户按Home键,

A.onPause () A.onStop()(——activityReferences == 0)(应用程序进入后台)

在这种情况下,如果用户从活动B按Home键而不是后退键,它仍然是一样的,activityReferences将是0。因此,我们可以检测作为应用程序进入后台。

那么,isActivityChangingConfigurations的角色是什么?在上面的场景中,假设活动B改变了方向。回调序列将是,

B.onPause () B.onStop()(——activityReferences == 0)(应用程序进入后台??) B.onDestroy () B.onCreate () B.onStart() (++activityReferences == 1)(应用程序进入前台??) B.onResume ()

这就是为什么我们有一个额外的isActivityChangingConfigurations检查,以避免活动正在经历配置更改的场景。

编辑:新的体系结构组件带来了一些有希望的东西:ProcessLifecycleOwner,参见@vokilam的回答


实际解决方案根据谷歌I/O谈话:

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

}

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

但还是有希望的。

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

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

生命周期。事件将返回应用程序的状态

ON_CREATE
ON_START
ON_RESUME
ON_PAUSE
ON_STOP
ON_DESTROY
ON_ANY

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

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

为此,您需要将此依赖项添加到构建中。gradle文件:

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

正如谷歌所建议的,你应该最小化在activity的生命周期方法中执行的代码:

一种常见的模式是实现依赖的操作 活动和片段的生命周期方法中的组件。 然而,这种模式会导致代码组织不佳,并且导致 错误的扩散。通过使用生命周期感知组件,您 是否可以将依赖组件的代码移出生命周期方法 以及组件本身。

你可以在这里阅读更多: https://developer.android.com/topic/libraries/architecture/lifecycle