检测应用何时 opened/resumed
Detect when app is opened/resumed
我想在每次应用 opened/closed 时使用服务器签入和签出用户,无论它是从任务抽屉启动还是恢复。有没有办法做到这一点,同时避免在每个 Activity?
中调用一个函数
谢谢!
好的。我将我的评论作为答案发布,因为提出问题的原始用户发现这真的很有帮助。
上述答案的问题在于,应用程序不想在 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
因此,为了更好地组织所需的会话管理功能,应使用以下结构。在MyApplication
的onCreate
中注册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
我想在每次应用 opened/closed 时使用服务器签入和签出用户,无论它是从任务抽屉启动还是恢复。有没有办法做到这一点,同时避免在每个 Activity?
中调用一个函数谢谢!
好的。我将我的评论作为答案发布,因为提出问题的原始用户发现这真的很有帮助。
上述答案的问题在于,应用程序不想在 activity 关闭时签入和签出,而是在应用程序启动或恢复时签入和签出。因此,当您在应用程序打开时关闭或在活动之间移动时,这可能会出现问题,这仍然会调用 oncreate() 和 onpause() 函数。
之前在Whosebug上也讨论过这个问题。下面是link.
How to detect when an Android app goes to the background and come back to the foreground
解决这个问题可能有不同的方法。以上 link 提供了有关如何解决它的更多见解。
编辑
在ProcessLifeCycleOwner
. See https://developer.android.com/topic/libraries/architecture/lifecycle
因此,为了更好地组织所需的会话管理功能,应使用以下结构。在MyApplication
的onCreate
中注册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