iHo*_*rse 369 android background foreground
我正在尝试编写一个应用程序,它会在经过一段时间后返回到前台时执行某些特定操作.有没有办法检测应用程序何时发送到后台或带到前台?
Mar*_*ini 184
2018年3月更新:现在有一个更好的解决方案.请参阅ProcessLifecycleOwner.您将需要使用新的体系结构组件1.1.0(目前最新),但它是专门为此而设计的.
这个答案提供了一个简单的示例,但我写了一个示例应用程序和一篇关于它的博客文章.
自从我在2014年写这篇文章以来,出现了不同的解决方案.有些工作,有些被认为是有效的,但有缺陷(包括我的!),我们作为一个社区(Android)学会了承担后果并为特殊案例编写了解决方法.
永远不要假设一个代码片段是您正在寻找的解决方案,情况不太可能; 更好的是,尝试了解它的作用以及它为什么这样做.
这个MemoryBoss类从来没有像我这里所写的那样实际使用过,它只是一段伪代码,恰好起作用.
除非你有充分的理由不使用新的架构组件(并且有一些,特别是如果你的目标是超级旧的api),那么继续使用它们.它们远非完美,但两者都不是ComponentCallbacks2.
更新/注释(2015年11月):人们一直在发表两条评论,首先是>=应该使用,而不是==因为文档声明您不应该检查确切的值.这是适用于大多数情况,但请记住,如果你只关心做事情时,应用程序去的背景下,你将不得不使用== 并且还与另一种解决方案(如活动生命周期回调)结合起来,或者你可能达不到你想要的效果.这个例子(这件事发生在我身上)是,如果您想要使用密码屏幕锁定应用程序(例如1Password,如果您熟悉它),如果您运行不足,可能会意外锁定您的应用程序在内存上并突然进行测试>= TRIM_MEMORY,因为Android会触发一个LOW MEMORY呼叫并且比你的呼叫更高.所以要小心你的测试方式.
此外,有些人询问如何检测您何时回来.
我能想到的最简单的方法解释如下,但由于有些人不熟悉它,我在这里添加了一些伪代码.假设你有YourApplication和你的MemoryBoss课程class BaseActivity extends Activity(你需要创建一个,如果你没有).
@Override
protected void onStart() {
super.onStart();
if (mApplication.wasInBackground()) {
// HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND
mApplication.setWasInBackground(false);
}
}
Run Code Online (Sandbox Code Playgroud)
我推荐onStart,因为Dialogs可以暂停一个活动,所以我打赌你不希望你的应用程序认为"它转到后台",如果你所做的只是显示全屏对话框,但你的里程可能会有所不同.
就这样.if块中的代码只会被执行一次,即使你转到另一个活动,新的(也会extends BaseActivity)将报告wasInBackground是false不会执行代码,直到onMemoryTrimmed被调用并且标志再次设置为true.
希望有所帮助.
更新/注释(2015年4月):在您对此代码进行全部复制和粘贴之前,请注意我发现了几个可能不是100%可靠的实例,必须与其他方法结合才能获得最佳结果.值得注意的是,有两个已知的实例,其中onTrimMemory不保证执行回调:
如果您的手机在您的应用程序可见时锁定屏幕(比如您的设备在nn分钟后锁定),则不会调用(或不总是)此回调,因为锁定屏幕位于顶部,但您的应用仍在"运行",尽管已覆盖.
如果您的设备内存相对较低(并且在内存压力下),操作系统似乎会忽略此调用并直接进入更关键的级别.
现在,根据您知道应用程序何时进入后台的重要性,您可能需要也可能不需要将此解决方案扩展到跟踪活动生命周期等等.
请记住以上内容并拥有一支优秀的QA团队;)
更新结束
可能会迟到,但在冰淇淋三明治(API 14)和上面有一个可靠的方法.
事实证明,当您的应用没有更多可见的UI时,会触发回调.您可以在自定义类中实现的回调称为ComponentCallbacks2(是的,带有两个).此回调仅适用于API级别14(冰淇淋三明治)及以上.
您基本上可以调用该方法:
public abstract void onTrimMemory (int level)
Run Code Online (Sandbox Code Playgroud)
该级别具体为20或更高
public static final int TRIM_MEMORY_UI_HIDDEN
Run Code Online (Sandbox Code Playgroud)
我一直在测试它,它总是有效,因为20级只是一个"建议",你可能想要释放一些资源,因为你的应用程序不再可见.
引用官方文档:
onTrimMemory(int)的级别:该进程一直在显示用户界面,并且不再这样做.此时应释放具有UI的大量分配,以便更好地管理内存.
当然,你应该实现它实际上做它所说的(清除在一定时间内没有使用的内存,清除一些未使用的集合,等等.可能性是无穷无尽的(参见官方文档了解其他可能更多)关键水平).
但是,有趣的是,操作系统告诉你:嘿,你的应用程序转到了后台!
这首先是你想要知道的.
你怎么决定什么时候回来?
好吧,这很简单,我确定你有一个"BaseActivity",所以你可以使用你的onResume()标记你回来的事实.因为只有当你实际接到上述onTrimMemory方法的电话时才会说你不回来.
有用.你不会得到误报.如果某项活动正在恢复,那么您将100%回来.如果用户再次回到后面,则会再次onTrimMemory()拨打电话.
您需要暂停您的活动(或者更好的是,自定义类).
保证始终收到此信息的最简单方法是创建一个这样的简单类:
public class MemoryBoss implements ComponentCallbacks2 {
@Override
public void onConfigurationChanged(final Configuration newConfig) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// We're in the Background
}
// you might as well implement some memory cleanup here and be a nice Android dev.
}
}
Run Code Online (Sandbox Code Playgroud)
为了使用它,在你的应用程序实现中(你有一个,RIGHT?),做类似的事情:
MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mMemoryBoss = new MemoryBoss();
registerComponentCallbacks(mMemoryBoss);
}
}
Run Code Online (Sandbox Code Playgroud)
如果你创建一个Interface你可以添加一个else,if并实现ComponentCallbacks(没有2)在API 14以下的任何东西.回调只有onLowMemory()方法,并没有被调用当你去后台,但你应该用它来修剪内存.
现在启动您的应用程序并按回家.onTrimMemory(final int level)应调用您的方法(提示:添加日志记录).
最后一步是从回调中取消注册.可能最好的地方是onTerminate()你的应用程序的方法,但是,该方法不会在真实设备上调用:
Run Code Online (Sandbox Code Playgroud)/** * This method is for use in emulated process environments. It will * never be called on a production Android device, where processes are * removed by simply killing them; no user code (including this callback) * is executed when doing so. */
因此,除非您确实存在不再需要注册的情况,否则您可以安全地忽略它,因为您的进程无论如何都会在操作系统级别死亡.
如果您决定在某个时间取消注册(例如,如果您为应用程序提供关闭机制以进行清理和死亡),您可以执行以下操作:
unregisterComponentCallbacks(mMemoryBoss);
Run Code Online (Sandbox Code Playgroud)
就是这样.
d60*_*402 174
以下是我设法解决这个问题的方法.它的前提是在活动转换之间使用时间参考很可能提供足够的证据证明应用程序已经"背景化".
首先,我使用了一个android.app.Application实例(我们称之为MyApplication),它有一个Timer,一个TimerTask,一个常量来表示从一个活动到另一个活动的合理转换所需的最大毫秒数(我去了)值为2s),以及一个布尔值来指示应用程序是否"在后台":
public class MyApplication extends Application {
private Timer mActivityTransitionTimer;
private TimerTask mActivityTransitionTimerTask;
public boolean wasInBackground;
private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
...
Run Code Online (Sandbox Code Playgroud)
该应用程序还提供了两种启动和停止计时器/任务的方法:
public void startActivityTransitionTimer() {
this.mActivityTransitionTimer = new Timer();
this.mActivityTransitionTimerTask = new TimerTask() {
public void run() {
MyApplication.this.wasInBackground = true;
}
};
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;
}
Run Code Online (Sandbox Code Playgroud)
此解决方案的最后一部分是从所有活动的onResume()和onPause()事件中添加对这些方法中的每一个的调用,或者最好是在所有具体活动继承的基本活动中:
@Override
public void onResume()
{
super.onResume();
MyApplication myApp = (MyApplication)this.getApplication();
if (myApp.wasInBackground)
{
//Do specific came-here-from-background code
}
myApp.stopActivityTransitionTimer();
}
@Override
public void onPause()
{
super.onPause();
((MyApplication)this.getApplication()).startActivityTransitionTimer();
}
Run Code Online (Sandbox Code Playgroud)
因此,在用户只是在应用程序的活动之间导航的情况下,离开活动的onPause()启动计时器,但几乎立即输入的新活动在计时器达到最大转换时间之前取消计时器.所以wasInBackground会是假的.
另一方面,当一个Activity从Launcher到达前台时,设备唤醒,结束通话等,很可能是在此事件之前执行的计时器任务,因此wasInBackground被设置为true.
Fre*_*ula 138
编辑:新架构组件带来了一些有希望的东西:ProcessLifecycleOwner,请参阅@ vokilam的回答
class YourApplication : Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(AppLifecycleTracker())
}
}
class AppLifecycleTracker : Application.ActivityLifecycleCallbacks {
private var numStarted = 0
override fun onActivityStarted(activity: Activity?) {
if (numStarted == 0) {
// app went to foreground
}
numStarted++
}
override fun onActivityStopped(activity: Activity?) {
numStarted--
if (numStarted == 0) {
// app went to background
}
}
}
Run Code Online (Sandbox Code Playgroud)
是.我知道很难相信这个简单的解决方案是有效的,因为我们这里有很多奇怪的解决方案.
但是有希望.
vok*_*lam 100
ProcessLifecycleOwner 似乎也是一个很有前途的解决方案.
ProcessLifecycleOwner将派出
ON_START,ON_RESUME事件,作为第一个活动移动通过这些事件.ON_PAUSE,,ON_STOP事件将在最后一个活动通过后延迟发送.此延迟足以保证在ProcessLifecycleOwner由于配置更改而销毁和重新创建活动时不会发送任何事件.
实现可以很简单
class AppLifecycleListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() { // app moved to foreground
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() { // app moved to background
}
}
// register observer
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())
Run Code Online (Sandbox Code Playgroud)
根据源代码,当前的延迟值是700ms.
使用此功能还需要dependencies:
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
Run Code Online (Sandbox Code Playgroud)
Swi*_*ind 90
在onPause()和onResume()当应用程序被带到后台,并到前台再次方法被调用.但是,当应用程序第一次启动并且在它被杀死之前,它们也会被调用.您可以在Activity中阅读更多内容.
没有任何直接的方式获取应用程序的状态,而在背景或前景,但即使我面临这个问题,并找到了解决方案onWindowFocusChanged和onStop.
有关详细信息,请查看Android:解决方案,以检测Android应用程序何时进入后台并返回前台,而不使用getRunningTasks或getRunningAppProcesses.
ric*_*kul 68
根据MartínMarconcinis的回答(谢谢!)我终于找到了一个可靠(非常简单)的解决方案.
public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName();
private static boolean isInBackground = false;
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if(isInBackground){
Log.d(TAG, "app went to foreground");
isInBackground = false;
}
}
@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() {
}
@Override
public void onTrimMemory(int i) {
if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){
Log.d(TAG, "app went to background");
isInBackground = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后将其添加到Application类的onCreate()中
public class MyApp extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
registerActivityLifecycleCallbacks(handler);
registerComponentCallbacks(handler);
}
}
Run Code Online (Sandbox Code Playgroud)
Nic*_*lov 61
我们使用这种方法.它看起来太简单了,但它在我们的应用程序中经过了充分测试,实际上在所有情况下工作都非常出色,包括通过"主页"按钮,"返回"按钮或屏幕锁定后进入主屏幕.试试看.
想法是,当处于前台时,Android总是在停止前一个活动之前启动新活动.这不是保证,但它是如何工作的.BTW,Flurry似乎使用相同的逻辑(只是一个猜测,我没有检查,但它挂钩相同的事件).
public abstract class BaseActivity extends Activity {
private static int sessionDepth = 0;
@Override
protected void onStart() {
super.onStart();
sessionDepth++;
if(sessionDepth == 1){
//app came to foreground;
}
}
@Override
protected void onStop() {
super.onStop();
if (sessionDepth > 0)
sessionDepth--;
if (sessionDepth == 0) {
// app went to background
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:根据评论,我们也在更高版本的代码中移动到onStart().此外,我正在添加超级调用,这些调用在我的初始帖子中缺失,因为这更像是一个概念而不是一个工作代码.
Emi*_*mil 54
如果您的应用包含多个活动和/或堆叠活动(如标签栏小部件),则覆盖onPause()和onResume()将无效.即,在开始新活动时,当前活动将在创建新活动之前暂停.完成(使用"后退"按钮)活动时也是如此.
我找到了两种似乎按照需要工作的方法.
第一个需要GET_TASKS权限,并且包含一个简单的方法,通过比较包名称来检查设备上的最高运行活动是否属于应用程序:
private boolean isApplicationBroughtToBackground() {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
这种方法在Droid-Fu(现在称为Ignition)框架中找到.
我实现自己的第二种方法不需要GET_TASKS权限,这很好.相反,实施起来要复杂一些.
在您的MainApplication类中,您有一个跟踪应用程序中正在运行的活动数的变量.在每个活动的onResume()中增加变量,在onPause()中减少它.
当运行活动的数量达到0时,如果满足以下条件,则将应用程序置于后台:
当您可以检测到应用程序已退回到后台时,很容易检测到它何时返回到前台.
Har*_*eet 33
创建一个扩展的类Application.然后我们可以使用它的覆盖方法onTrimMemory().
要检测应用程序是否转到后台,我们将使用:
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Works for Activity
// Get called every-time when application went to background.
}
else if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // Works for FragmentActivty
}
}
Run Code Online (Sandbox Code Playgroud)
Old*_*664 18
考虑使用onUserLeaveHint.这只会在您的应用进入后台时调用.onPause将有角落案件要处理,因为它可以出于其他原因被调用; 例如,如果用户在您的应用中打开了另一项活动(例如您的设置页面),即使它们仍在您的应用中,您的主要活动的onPause方法也会被调用; 当你可以简单地使用onUserLeaveHint回调来跟踪你所要求的内容时,跟踪将会导致错误.
在调用UserLeaveHint时,可以将boolean inBackground标志设置为true.当调用onResume时,如果设置了inBackground标志,则只假设您回到前台.这是因为如果用户只是在您的设置菜单中并且从未离开过该应用,则还会在您的主活动上调用onResume.
请记住,如果用户在设置屏幕中点击主页按钮,则会在您的设置活动中调用onUserLeaveHint,当它们返回onResume时,将在您的设置活动中调用.如果您的主要活动中只有此检测代码,您将错过此用例.要在所有活动中使用此代码而不重复代码,请使用扩展Activity的抽象活动类,并将公共代码放入其中.然后,您拥有的每个活动都可以扩展此抽象活动.
例如:
public abstract AbstractActivity extends Activity {
private static boolean inBackground = false;
@Override
public void onResume() {
if (inBackground) {
// You just came from the background
inBackground = false;
}
else {
// You just returned from another activity within your own app
}
}
@Override
public void onUserLeaveHint() {
inBackground = true;
}
}
public abstract MainActivity extends AbstractActivity {
...
}
public abstract SettingsActivity extends AbstractActivity {
...
}
Run Code Online (Sandbox Code Playgroud)
Ren*_*eno 13
ActivityLifecycleCallbacks可能是有意义的,但它没有很好的文档记录.
但是,如果调用registerActivityLifecycleCallbacks(),则应该能够在创建,销毁等活动时获得回调.您可以为Activity 调用getComponentName().
mat*_*dev 11
该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的建议,您应该最小化在生命周期活动方法中执行的代码:
一种常见模式是在活动和片段的生命周期方法中实现依赖组件的操作.但是,这种模式导致代码组织不良和错误扩散.通过使用生命周期感知组件,您可以将依赖组件的代码移出生命周期方法并移入组件本身.
您可以在这里阅读更多内容:https: //developer.android.com/topic/libraries/architecture/lifecycle
在您的应用程序中添加回调并检查root活动,方式如下:
@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();
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
我在Github app-foreground-background-listen上创建了一个项目
为应用程序中的所有Activity创建BaseActivity.
public class BaseActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
public static boolean isAppInFg = false;
public static boolean isScrInFg = false;
public static boolean isChangeScrFg = false;
@Override
protected void onStart() {
if (!isAppInFg) {
isAppInFg = true;
isChangeScrFg = false;
onAppStart();
}
else {
isChangeScrFg = true;
}
isScrInFg = true;
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
if (!isScrInFg || !isChangeScrFg) {
isAppInFg = false;
onAppPause();
}
isScrInFg = false;
}
public void onAppStart() {
// Remove this toast
Toast.makeText(getApplicationContext(), "App in foreground", Toast.LENGTH_LONG).show();
// Your code
}
public void onAppPause() {
// Remove this toast
Toast.makeText(getApplicationContext(), "App in background", Toast.LENGTH_LONG).show();
// Your code
}
}
Run Code Online (Sandbox Code Playgroud)
现在使用此BaseActivity作为所有Activity的超类,如MainActivity扩展BaseActivity,并在启动应用程序时调用onAppStart,并在应用程序从任何屏幕进入后台时调用onAppPause().
使用ProcessLifecycleOwner非常简单
添加这些依赖项
implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"
Run Code Online (Sandbox Code Playgroud)
在Kotlin:
class ForegroundBackgroundListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startSomething() {
Log.v("ProcessLog", "APP IS ON FOREGROUND")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopSomething() {
Log.v("ProcessLog", "APP IS IN BACKGROUND")
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的基础活动中:
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get()
.lifecycle
.addObserver(
ForegroundBackgroundListener()
.also { appObserver = it })
}
Run Code Online (Sandbox Code Playgroud)
请参阅我关于此主题的文章:https: //medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48
没有直接的生命周期方法可以告诉您整个应用程序何时进入后台/前台。
我用简单的方法做到了这一点。按照以下说明检测应用程序后台/前台阶段。
通过一些解决方法,这是可能的。在这里,ActivityLifecycleCallbacks来救援。让我一步一步来。
首先,创建一个扩展android.app.Application并实现ActivityLifecycleCallbacks接口的类。在 Application.onCreate() 中,注册回调。
public class App extends Application implements
Application.ActivityLifecycleCallbacks {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
}
Run Code Online (Sandbox Code Playgroud)
在清单中注册“App”类,如下所示<application android:name=".App"。
当应用在前台时,至少有一个处于启动状态的 Activity,当应用处于后台时,将没有处于启动状态的 Activity。
在“App”类中声明如下2个变量。
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
Run Code Online (Sandbox Code Playgroud)
activityReferences将保持开始状态的活动数量计数。isActivityChangingConfigurations是一个标志,用于指示当前 Activity 是否正在经历配置更改,如方向切换。
使用以下代码,您可以检测应用程序是否处于前台。
@Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
Run Code Online (Sandbox Code Playgroud)
这是检测应用程序是否进入后台的方法。
@Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
Run Code Online (Sandbox Code Playgroud)
这个怎么运作:
这是通过按顺序调用 Lifecycle 方法的方式完成的一个小技巧。让我演练一个场景。
假设用户启动了 App,启动了 Launcher Activity A。生命周期调用将是,
A.onCreate()
A.onStart() (++activityReferences == 1)(App进入前台)
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)(应用进入后台)
万一,如果用户从 Activity B 按下 Home 按钮而不是 Back 按钮,它仍然是相同的并且 activityReferences 将是0。因此,我们可以检测到应用程序进入后台。
那么,它的作用是isActivityChangingConfigurations什么?在上面的场景中,假设 Activity B 改变了方向。回调序列将是,
B.onPause()
B.onStop() (--activityReferences == 0)(应用进入后台??)
B.onDestroy()
B.onCreate()
B.onStart() (++activityReferences == 1)(应用进入前台??)
B.onResume()
这就是为什么我们有一个额外的检查isActivityChangingConfigurations来避免 Activity 经历配置更改时的情况。
您可以使用ProcessLifecycleOwner为其附加生命周期观察器。
public class ForegroundLifecycleObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onAppCreated() {
Timber.d("onAppCreated() called");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppStarted() {
Timber.d("onAppStarted() called");
}
@OnLifecycleEvent(Event.ON_RESUME)
public void onAppResumed() {
Timber.d("onAppResumed() called");
}
@OnLifecycleEvent(Event.ON_PAUSE)
public void onAppPaused() {
Timber.d("onAppPaused() called");
}
@OnLifecycleEvent(Event.ON_STOP)
public void onAppStopped() {
Timber.d("onAppStopped() called");
}
}
Run Code Online (Sandbox Code Playgroud)
然后在onCreate()您的Application类的上调用此代码:
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());
Run Code Online (Sandbox Code Playgroud)
这样,你就能捕捉到的事件ON_PAUSE和ON_STOP你的应用程序时,它会在后台这种情况发生。
| 归档时间: |
|
| 查看次数: |
273103 次 |
| 最近记录: |