检测应用何时 opened/resumed

Detect when app is opened/resumed

我想在每次应用 opened/closed 时使用服务器签入和签出用户,无论它是从任务抽屉启动还是恢复。有没有办法做到这一点,同时避免在每个 Activity?

中调用一个函数

谢谢!

您可以查看 Application.registerActivityLifecycleCallbacks() &c.

好的。我将我的评论作为答案发布,因为提出问题的原始用户发现这真的很有帮助。

上述答案的问题在于,应用程序不想在 activity 关闭时签入和签出,而是在应用程序启动或恢复时签入和签出。因此,当您在应用程序打开时关闭或在活动之间移动时,这可能会出现问题,这仍然会调用 oncreate() 和 onpause() 函数。

之前在Whosebug上也讨论过这个问题。下面是link.

How to detect when an Android app goes to the background and come back to the foreground

解决这个问题可能有不同的方法。以上 link 提供了有关如何解决它的更多见解。

编辑

, matdev brought to my attention the more modern approach to listening to app lifecycle events via ProcessLifeCycleOwner. See https://developer.android.com/topic/libraries/architecture/lifecycle

因此,为了更好地组织所需的会话管理功能,应使用以下结构。在MyApplicationonCreate中注册SessionTracker。然后将与跟踪用户会话相关的功能隔离到 SessionTracker class.

首先添加到你的build.gradle

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

然后,执行以下操作:

public class MyApplication extends Application {  

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

public class SessionTracker implements LifecycleObserver {
    private static SessionTracker sSessionTracker;
    private static final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;  // Time allowed for transitions

    private Timer mStopDelayTimer;
    private TimerTask mActivityTransitionTimerTask;
    private boolean mWasInBackground = true;
    private AppSession mAppSession;

    public static SessionTracker getInstance() {
        if (sSessionTracker == null) {
            sSessionTracker = new SessionTracker();
        }
        return sSessionTracker;
    }

    private SessionTracker() {
        // no-op
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private void onLifecycleStop() {
        submitAppSession(appSession);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onLifecycleStart() {
        mAppSession = new AppSession();
    }

    private void submitAppSession(AppSession appSession) {
        // TODO submit app session here
    }
}

public class AppSession {
    /* TODO */
}

上一个答案

d60402 提供的答案 here and the suggestion by Hanno Binder to register activity callbacks using Application.registerActivityLifecycleCallbacks() 让我找到了这个解决方案。

我扩展了应用程序并将回调注册到 Activity 方法 onPause 和 onStart,如下所示。在这些方法中,计时器是 started/stopped(一个 activity 在调用 onPause 的地方退出,在调用 onStart 的地方进入一个新的计时器)。当应用确定在 background/foreground (true/false) 中时,标志 "wasInBackground" 被切换。如果当 onStart 回调为 运行 时应用程序处于后台,则调用 "appEntered"。如果 onPause 和 onStart 回调之间传递的时间大于指定时间(为 activity 转换提供足够的时间),则在认为应用程序会话完成的地方调用 "appExited"。

public class MyApplication extends Application {

public static final String LOG_TAG = "MyApp";

public boolean wasInBackground = true;

private AppSession appSession;
private Timer mActivityTransitionTimer;
private TimerTask mActivityTransitionTimerTask;
private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;  // Time allowed for transitions

Application.ActivityLifecycleCallbacks activityCallbacks = new Application.ActivityLifecycleCallbacks() {

    @Override
    public void onActivityResumed(Activity activity) {

        if (wasInBackground) {
            //Do app-wide came-here-from-background code
            appEntered();
        }
        stopActivityTransitionTimer();
    }

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

    ...

};

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

public void startActivityTransitionTimer() {
    this.mActivityTransitionTimer = new Timer();
    this.mActivityTransitionTimerTask = new TimerTask() {
        public void run() {
            // Task is run when app is exited
            wasInBackground = true;
            appExited();
        }
    };

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

private void appEntered() {
    Log.i(LOG_TAG, "APP ENTERED");

    appSession = new AppSession();
}

private void appExited() {
    Log.i(LOG_TAG, "APP EXITED");

    appSession.finishAppSession();

    // Submit AppSession to server
    submitAppSession(appSession);
    long sessionLength = (appSession.getT_close() - appSession.getT_open())/1000L;
    Log.i(LOG_TAG, "Session Length: " + sessionLength);
}

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的建议,您应该尽量减少在活动的生命周期方法中执行的代码:

A common pattern is to implement the actions of the dependent components in the lifecycle methods of activities and fragments. However, this pattern leads to a poor organization of the code and to the proliferation of errors. By using lifecycle-aware components, you can move the code of dependent components out of the lifecycle methods and into the components themselves.

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