检测应用程序何时打开/恢复

Tom*_*lin 8 android data-collection

每次打开/关闭应用程序时,无论是从任务抽屉启动还是恢复,我都希望在服务器上签入和签出用户.有没有办法做到这一点,同时避免在每个活动中调用一个函数?

谢谢!

Tom*_*lin 9

编辑

这个答案中,matdev引起了我更多的现代方法来监听应用程序生命周期事件ProcessLifeCycleOwner.请参阅https://developer.android.com/topic/libraries/architecture/lifecycle

因此,为了更好地组织期望的会话管理功能,应该使用以下结构.注册SessionTrackeronCreateMyApplication.然后将与跟踪用户会话相关的功能隔离到SessionTracker该类.

首先添加到build.gradle

dependencies {
    implementation "android.arch.lifecycle:extensions:1.1.1"
}
Run Code Online (Sandbox Code Playgroud)

然后,实现以下内容:

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 */
}
Run Code Online (Sandbox Code Playgroud)

以前的答案

由d60402提供的答案在这里的汉诺粘合剂和建议使用登记活动回调Application.registerActivityLifecycleCallbacks()使我这个解决方案.

我将Application和注册的回调扩展到Activity方法onPause和onStart,如下所示.在这些方法中,启动/停止计时器(一个活动被退出,其中调用onPause,在调用onStart时输入一个新活动).当应用确定在后台/前景(真/假)时,标记"wasInBackground"被切换.如果在运行onStart回调时应用程序处于后台,则会调用"appEntered".如果在onPause和onStart回调之间传递的时间大于指定的时间(为活动转换提供足够的时间),则会调用应用程序会话的"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);
}
Run Code Online (Sandbox Code Playgroud)


mat*_*dev 6

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

dependencies {
    implementation "android.arch.lifecycle:extensions:1.1.1"
}
Run Code Online (Sandbox Code Playgroud)

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

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

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