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


当前回答

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

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

只要有一点变通办法,这是可能的。在这里,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检查,以避免活动正在经历配置更改的场景。

其他回答

这是我的解决方案。只需在您的主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)
    {

    }
}

正确答案

创建名为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);

完成了!现在当应用程序在后台时,我们得到日志状态:我们退出 当我们进入app,我们得到log status,我们是out

在你的应用程序中添加回调并检查根活动,如下所示:

@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();
            }
        }
    });
}

我设法监控应用导航到后台和回前台通过实现一个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之后,你只需要将这个activity扩展到应用程序中的任何activity。

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

我希望这对你有帮助:)

My app needs to "reboot" after return from background - show a series of activities, according to client solicitations. After extensive search on how to manage the background/foreground transitions (treated very differently between iOS and Android), I crossed this question. Found very useful help here, specially from the most voted answer and the one flagged as correct. However, simply reinstantiate the root activity EVERY TIME the app enters foreground looked too annoying, when you think about UX. The solution that worked for me, and the one I think's most adequated - based on the Youtube and Twitter apps functionality - was to combine the answers from @GirishNair and @d60402: Calling the timer when the app's trimming memory, as follows:

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

    super.onTrimMemory(level);
}

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

private final long MAX_ACTIVITY_TRANSITION_TIME = 30000;

当app进入前台,重新启动,或者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();
    }
}

在我的情况下,当应用程序在最大时间后进入前台时,会创建一个新任务,因此stopActivityTransitionTimer()在onActivityCreated()或onActivityDestroyed()上被调用,在应用程序扩展类中-转向不必要调用活动中的方法。 希望能有所帮助。