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

Android 检测应用程序何时打开/恢复,android,data-collection,Android,Data Collection,我希望在每次打开/关闭应用程序时,无论是从任务抽屉启动还是恢复,都能使用服务器签入和签出用户。是否有一种方法可以做到这一点,同时避免在每个活动中调用函数 谢谢大家! 您可以使用oncreate()和onpause()方法。您可以查看&c.好的。我将我的评论作为答案,因为问这个问题的原始用户发现这非常有用 上述答案的问题在于,应用程序不希望在活动关闭时签入和签出,而是在应用程序启动或恢复时签入和签出。因此,当您关闭或在活动之间移动时,当您打开应用程序时,这可能会出现问题,应用程序仍将调用oncre

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


谢谢大家!

您可以使用
oncreate()
onpause()
方法。

您可以查看&c.

好的。我将我的评论作为答案,因为问这个问题的原始用户发现这非常有用

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

在前面的stackoverflow中也讨论了这个问题。下面是链接

解决这个问题可能有不同的方法。以上链接提供了有关如何解决此问题的更多信息。

编辑

在年,matdev提请我注意通过
ProcessLifeCycleOwner
收听应用程序生命周期事件的更现代的方法。看

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

首先添加到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提供的答案和Hanno Binder关于使用注册活动回调的建议使我找到了这个解决方案

我扩展了应用程序并注册了对活动方法onPause和onStart的回调,如下所示。在这些方法中,启动/停止计时器(在调用onPause时退出一个活动,在调用onStart时输入一个新活动)。当应用程序确定位于背景/前景(真/假)时,将切换标志“wasInBackground”。如果应用程序在后台运行onStart回调,则调用“appEntered”。如果onPause和onStart回调之间经过的时间大于指定的时间(为活动转换提供足够的时间),则在认为应用程序会话已完成的位置调用“AppExit”

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

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

您可以在此处阅读更多内容:

创建一个为您设置标记的活动,并扩展该类,而不是将活动扩展到您当前的活动。这样,您只需编写一次代码。@zgc7009提出了一个通常效果良好的想法。问题是,如果您的某些活动需要扩展来自其他库的一些已经专门化的活动变体,那么您也必须为其制作一个特殊版本。@ChrisStratton也不希望在活动关闭时签入和签出,而是在应用程序启动或恢复时签入和签出。因此,当您关闭或在活动之间移动时,当您打开应用程序时,这可能会出现问题。@ngoa-是的,它可以,尽管让活动从单例中的某个跟踪器注册和注销可以处理它。您还可以加入一个小计时器,这样在暂停/停止之后的适当时间内,您才可以注册离开,而没有后续的恢复/开始。@TomMcFarlin请参考这个已经提出的问题,因为这可以帮助您。如果目标API 14+(Android 4.x或更高版本)是可以接受的,这是一个非常有趣的想法,尽管尚未实现这一点,但在访问文档并查阅@ngoa()提供的链接后,我相信这会很好。谢谢你的洞察力@汤姆麦克法林,谢谢。我会将此作为答案发布。@ngoa您能告诉我们,为什么部分(in)是正确的吗?@RenéHoffmann正如我在问题下的评论中提到的,他不希望在活动结束时签入和签出,而是在应用程序启动或恢复时签入和签出。因此,当你关闭或在活动之间移动时,当你打开应用程序时,这可能会出现问题,它仍然会调用
oncreate()
onpause()
函数。谢谢你的回答,我将在下周内实现这一点。将重新讨论该问题以澄清我的问题并添加到讨论中。最好在onActivityResumed和OnActivityPassued中进行此操作,因为当其他活动处于前台时,活动可以停止。否则就太棒了@阿卡什真是个好电话。虽然我也可以看到onActivityStarted/onActivityStopped可能被证明是合适的情况。我已经更新了答案以反映您的反馈。简短的谷歌搜索并没有给出我想要的答案,所以可能需要一个快速的实验。我相信聊天室和其他部分阻碍查看(即使几乎全部)的应用程序会导致在底层(您的)应用程序上调用OnActivity。由于用户通常打算继续部分可见的应用程序,因此您可能希望