Activity中的onPause()和onStop()方法

22

我是Android开发的新手,仍然无法理解活动中的onPause()onStop()方法。

在我的应用程序中,我有一个名为Counter的静态类,它在内存中保留了应用程序变量的状态。我的应用程序在模拟器中运行良好。我尝试测试onPause()onStop()的差异行为。

对于onPause,我希望保留Counter类成员中存储的值,而调用onStop()时,我希望将计数器值重置为零。因此,我覆盖了onStop()并将计数器类内部的变量设置为零。但是,在模拟器中,我似乎无法使应用程序处于暂停状态。在模拟器中,我打开我的应用程序并进行操作。然后我按模拟器的主页按钮(而不是返回按钮),启动另一个应用程序,认为这会模仿onPause()活动。但是,模拟器似乎不遵守这一点(我正在使用一个armeabi v7a模拟器),它似乎总是调用onStop(),因为我的计数器值都恢复为零,根据我在onStop()中的重写。这是模拟器固有的问题,还是我做错了某些事情,以便使我的活动处于暂停状态?


2
你能否包含代码以强调你的问题? - t0mm13b
6个回答

26

我不确定你正在使用哪个模拟器进行测试,但 onPause 是唯一一个在你的Activity失去焦点时保证始终被调用的方法(我说“始终”是因为在某些设备上,特别是运行 Android 3.2+ 的设备上,在Activity被销毁之前,onStop 并不总是被保证会被调用)。

对于初学者来说,了解 Activity 生命周期的好方法是在重写的方法中添加 Log。例如:

public class SampleActivity extends Activity {

    /**
     * A string constant to use in calls to the "log" methods. Its
     * value is often given by the name of the class, as this will 
     * allow you to easily determine where log methods are coming
     * from when you analyze your logcat output.
     */
    private static final String TAG = "SampleActivity";

    /**
     * Toggle this boolean constant's value to turn on/off logging
     * within the class. 
     */
    private static final boolean VERBOSE = true;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (VERBOSE) Log.v(TAG, "+++ ON CREATE +++");
    }

    @Override
    public void onStart() {
        super.onStart();
        if (VERBOSE) Log.v(TAG, "++ ON START ++");
    }

   @Override
    public void onResume() {
        super.onResume();
        if (VERBOSE) Log.v(TAG, "+ ON RESUME +");
    }

    @Override
    public void onPause() {
        super.onPause();
        if (VERBOSE) Log.v(TAG, "- ON PAUSE -");
    }

    @Override
    public void onStop() {
        super.onStop();
        if (VERBOSE) Log.v(TAG, "-- ON STOP --");
    }

   @Override
    public void onDestroy() {
        super.onDestroy();
        if (VERBOSE) Log.v(TAG, "- ON DESTROY -");
    }
}

谢谢Alex,我已经有了日志标记,我应该提到这一点。日志向我展示的是onPause()确实被调用了。对于我来说,在模拟器中的问题是我不希望调用onStop()。所以当我按下主页按钮时,我的日志向我展示onPause()确实被调用了,这是预期的。然而,当我在模拟器中切换应用程序(例如从我的应用程序切换到Web浏览器),我的日志也向我展示我的应用程序的onStop()正在被调用。我希望只有在系统资源不足时才会调用onStop(),也许VM是? - Stephan Doliov
嗯...你有没有在开发者设置里乱搞?设置-->开发者选项-->销毁所有活动,或许被勾选了?除此之外,重要的是要明白onStop不一定会被调用...就像这里看到的:http://bit.ly/OMB0as - Alex Lockwood
@StephanDoliov 我提到检查开发者设置,因为onStop从未被调用似乎很奇怪。我不确定为什么会发生这种情况。但我敢打赌,如果你在实际设备上测试,你不会得到相同的行为。当你按下“主页”按钮时会发生什么?这是调用onStop的一种常见方式。 - Alex Lockwood
需要注意的是,在 post-Honeycomb 设备中,onStop() 方法现在可以得到保证会被调用。详情请见:https://dev59.com/lV0b5IYBdhLWcg3wQPbw - Kenny Worden
现在是2018年。但是文档显示onStop()对所有版本都可以kill掉,而onPause()则在蜂巢版本之前就可以kill掉 - https://i.imgur.com/CYpQdSL.png (https://developer.android.com/reference/android/app/Activity.html) - Cheok Yan Cheng
谢谢,我处理一个漏洞已经好几天了,不知道发生了什么,这些日志救了我! - Daniel Beltrami

13

我知道你的问题是6个月前的,但以防其他人也遇到了这个问题:

我做错了什么导致我的活动进入暂停状态。

是的,你做错了。这样做:

我按下模拟器的主页按钮(不是返回按钮),然后启动另一个应用程序,认为这将模拟onPause()活动。

按下主页按钮确实会调用 onPause()方法,但由于主页按钮使您的活动不再可见,因此它会调用 onStop()方法(就像patriot和milter提到的那样)。

根据Activities开发者参考文献(http://developer.android.com/guide/components/activities.html),您可以显示对话框或将设备简单置于睡眠状态。

或者,您可以调用一个只部分遮挡调用活动的活动。因此,调用一个创建具有大小视图的窗口的活动:

 android:layout_width="100dp"
 android:layout_height="100dp"

界面不覆盖整个屏幕,因此呼叫活动部分可见,从而只调用呼叫活动的onPause()方法。

克隆该活动,使两个视图大小均为“match_parent”,而不是“100dp”,然后调用呼叫活动和呼叫活动的onPause()onStop()方法将被同时调用,因为呼叫活动将不可见。

当然可能会有例外情况,比如被调用的活动在其onCreate()onStart()onResume()中导致应用程序崩溃,那么呼叫活动的onStop()显然就不会被调用了。我只是在讨论一般情况。


4
当调用onPause()和onStop()时,两者之间的差异可能非常微妙。然而,正如这里所解释的那样,当另一个activity获取焦点(例如弹出窗口或透明窗口)而当前activity仍在运行时,通常会执行onPause()。如果您完全离开应用程序(例如按下主页按钮),则该activity不再可见,系统可能会执行onStop()。我只是说可能,因为像Alex提到的那样,在Activity被销毁之前,有一些情况下不会调用onStop()。

如何确保在点击返回按钮或调用finish()后onStop()方法会被调用? - Amit

2

onPause():

"如果一个活动失去了焦点但仍然可见(也就是说,一个新的非全屏或透明的活动在你的活动上面拥有焦点),那么它就会被暂停。暂停的活动完全处于活动状态(它保持所有状态和成员信息,并保持与窗口管理器的连接),但在极端低内存情况下,系统可能会将其杀死。"

onStop():

"如果一个活动被完全遮挡,那么它就会被停止。它仍然保留所有状态和成员信息,但它对用户不再可见,因此它的窗口被隐藏,并且在需要其他地方的内存时,它经常会被系统杀死。"

摘自Android参考活动类:http://developer.android.com/reference/android/app/Activity.html


1

如果您正在模拟 Android 4.x,您可以使用“设置” ->“开发人员选项” ->“不保留活动”和“后台进程限制”来控制系统处理后台活动的方式。对于旧版本,有一个名为 Dev Tools 的应用程序,其中包含相同的设置。但是,在低内存条件下,系统可能会忽略这些设置并终止您的应用程序。增加分配给模拟器的内存量可能会有所帮助。

此外,如果您从 Eclipse 重新启动应用程序,则会杀死先前的进程而不是优雅地终止它。


1

我同意milter的观点!

onPause():

"如果一个activity失去了焦点但仍可见(也就是说,一个新的非全屏或透明的activity已经在你的activity上方拥有了焦点),它就会被暂停。暂停的activity完全存活着(它维护着所有的状态和成员信息,并保持连接到窗口管理器),但在极端低内存情况下,系统可能会将其杀死。"

如果您在不按返回键的情况下切换应用程序(按住HOME键),那么操作系统将调用onPause。当您返回到您的activity时(再次按住HOME键),在onResume中,您应该已经保留了所有私有变量。但是您无法控制用户,对吧?!

如果您预期用户要离开您的应用程序并且操作系统调用了您的onStop,如果您打算恢复离开时的状态,则最好保存您的数据。

我还有一个定时器,我需要保存经过的时间,以便用户返回时可以恢复数据。 这是我的保存示例:

@Override 
public void onSaveInstanceState(Bundle savedInstanceState) { 
  super.onSaveInstanceState(savedInstanceState); 
  // Save UI state changes to the savedInstanceState. 
  // This bundle will be passed to onCreate if the process is 
  // killed and restarted. 

  savedInstanceState.putLong("elapsedTime", elapsedTime);
  // etc. 
} 

并且我的代码用于恢复:

@Override 
public void onRestoreInstanceState(Bundle savedInstanceState) { 
  super.onRestoreInstanceState(savedInstanceState); 
  // Restore UI state from the savedInstanceState. 
  // This bundle has also been passed to onCreate. 

  elapsedTime = savedInstanceState.getLong("elapsedTime");
} 

把这些方法放到你的类里,就可以开始使用了。请记住,在我的情况下,字符串“elapsedTime”是系统的关键字,必须是唯一的。对于每个要保存的数据,请使用唯一的字符串。例如,“startClock”,“ClockTextColor”等...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接