Android活动的onPause()和onStop()有什么区别?

170
根据 android 开发文档,当一个 Activity 进入前台时将会调用 onPause() 方法,而当它不再可见时将会调用 onStop() 方法。
“Activity 进入前台” 和 “Activity 不再可见” 难道不是同一个意思吗?请问它们之间有什么区别呢?

20
对于这个出色的问题点赞。同时,“暂停”状态的活动是完全存在的(它维护所有状态和成员信息,并保持连接到窗口管理器)。一个“停止”状态的活动也保留了所有状态和成员信息,但不再连接到窗口管理器。 - ateiob
8个回答

116

不,如果某个活动进入前台,这不一定意味着另一个活动完全不可见。考虑以下情况:

Activity with the theme Theme.Dialog

在这里,我们同时看到了两个活动。带有字段的第一个活动被另一个活动遮挡,用户无法再与其交互。然而,它仍然是可见的,并具有所有相应的影响。

这就留下了一个问题,哪个活动被认为是完全不透明并覆盖整个屏幕,哪个不是。这个决定基于包含活动的窗口。如果窗口具有标志windowIsFloatingwindowIsTranslucent,则认为该活动不会使底层内容不可见,否则会并导致调用onStop()。相关代码可以在com.android.server.am.ActivityRecord中找到:

fullscreen = ent != null && !ent.array.getBoolean(
        com.android.internal.R.styleable.Window_windowIsFloating, false)
        && !ent.array.getBoolean(
        com.android.internal.R.styleable.Window_windowIsTranslucent, false);

10
如果能够提供一个关于部分可见性和完全可见性的出色解释,那就加1分。了解Android在屏幕阈值百分比方面做出onPause()onStop()决策的门槛是很有趣的。它是否为100%?如果前一个活动只有一个像素可见,那么它仍然是onPause()吗? - ateiob
3
虽然没有明确说明,但我认为是这样的。通常情况下很明显,因为大多数不占据整个屏幕的活动都会使用系统提供的对话框样式之一。 - Malcolm
1
很奇怪,但在我的应用程序中,当显示对话框时根本不会调用onPause()。只有在我按下主页按钮时才会调用onPause()。这怎么可能? - ateiob
3
一项活动。这是重点:并非每个对话都实际上是对话。你可以让一项活动看起来像是对话,因此它实际上比整个屏幕小。 - Malcolm
我们可以说在活动从可见状态(在onResume()调用之后)转换为不可见状态(在onStop()调用之前),onPause()会被调用吗? - Srinivasan N
显示剩余4条评论

48
如果你仍然可以看到它的任何部分(Activity回到前台时,要么没有占据整个屏幕,要么有点透明),将会调用onPause()。如果你无法看到它的任何部分,将会调用onStop()
例如,一个对话框可能不会覆盖整个之前Activity,这就是调用onPause()的时候。
**我在这里不是指Android Dialog,而是指一个弹出并只遮挡部分用户屏幕的概念性想法。这条注释是为了澄清@ GMsoF的评论而添加的。

36
不。这是误导性的。弹出对话框不会调用onPause()方法,因为它使用当前活动的上下文,即认为活动仍然存活。 - Sam YC
6
听起来好像当我提到“dialog”时,你误以为我是指Android类中的“Dialog”。不过我的意思是,使用一些东西来部分地遮挡第一个“Activity”,以此说明所有新的“Activity”并不需要完全覆盖之前的内容。请注意,避免改变原文的含义。 - nicholas.hauschild

24
实际上,我们应该考虑“onPause()”和“onPause() + onStop()”之间的区别。每当发生新活动并占用屏幕的部分空间时,你以前运行的活动仍然在某种程度上可见。在这种情况下,以前运行的活动不会被推到后台堆栈中,因此只调用了onPause()方法。另一方面,如果发生一些新的活动并占据整个屏幕,使得以前运行的活动消失,那么以前运行的活动将被移动到后台堆栈中,这时会调用onPause() + onStop()。总之,onPause()表示屏幕被其他新活动部分覆盖,活动未移动到后台堆栈;而onPause() + onStop()表示屏幕被其他新活动完全覆盖,活动已移动到后台堆栈。了解更多关于后台堆栈的信息。

11

处于前台意味着该活动具有输入焦点。例如,一个活动可以是可见的,但被具有焦点的对话框部分遮挡。在这种情况下,将调用onPause(),但不会调用onStop()。当对话框消失时,将调用活动的onResume()方法(但不会调用onStart())。


5
对话框可能会让人误解。假设从此活动的主UI线程弹出警告对话框,则在这种情况下不会调用onPause()。只有在该对话框是从其他活动或其他应用程序弹出时才会调用。 - Sam003
1
@Zhisheng - 我同意你的评论。我只是在转述活动指南主题:_"onPause()在设备进入睡眠状态或对话框出现时被调用"_。正如这个线程所表明的那样,一个对话框并不一定意味着一个活动已经暂停了(尽管对于像作为对话框显示的活动这样的活动来说,它确实会被暂停)。 - Ted Hopp

2
每当一个新的ACTIVITY开始时,无论什么情况下都会调用前一个Activity的onPause。实际上有两种情况:
1- 前一个Activity的一部分可见或者新的Activity是透明的:只会调用onPause。
2- 新的Activity完全覆盖了前一个Activity:会同时调用onPause和onStop。
----需要注意以下几点:
注意1:如果一个对话框在Activity之上启动,则不会调用任何onPause或onStop。
注意2:如果它是一个主题设置为对话框的Activity,则行为将像普通Activity一样。
注意3:显然,类似Marshmallow权限对话框这样的系统对话框会导致onPause。

0
简而言之:
当另一个活动显示时,前一个活动生命周期方法的 onStop() 会被调用。当您在活动顶部有对话框时,onPause() 会被调用。
注意:活动是填充整个屏幕的组件。
注意:对话框不是活动,因为它们不完全填充屏幕。

0
我在使用onPause和onStop方法时遇到了很多问题,因此我将澄清我遇到的三种情况-
1. 当您点击最近使用的应用程序按钮时,不会调用任何生命周期方法,但是onWindowFocusChanged(boolean hasFocus)会被调用,并且hasFocus值为false。在Android 5之前的版本中,按下最近使用的应用程序按钮会调用onPause方法。

2. 当弹出窗口(如Malcolm所述)出现在您的活动上时,将调用onPause按钮。如果调用了占据整个屏幕的新活动,则在先前的活动上调用onStop。Android permission dialog也会导致您的活动调用onPause。

3. 如果您的活动超时,则会调用onPause。一段时间后,如果您不打开屏幕,则将调用onStop。

还有一个重要的事情由ateiob提到,这完善了答案

一个暂停的活动是完全存活的(它保持所有状态和成员信息,并保持连接到窗口管理器)。一个停止的活动也保留所有状态和成员信息,但不再连接到窗口管理器。
希望对您有所帮助。

1
感谢最近的应用程序按钮。我在API 30上按下它,onPause被调用了。 - CoolMind

-5

是的,我尝试理解并可以以下面的方式解释:

有两个活动:ActivityA和ActivityB

public class ActivityA extends Activity implements OnClickListener {

// button
private Button mBtnChangeActivity;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_a);
    initialize();
    setEvent();
}

private void initialize() {
    Log.i("Activity A", "Initialize()");
    mBtnChangeActivity = (Button) findViewById(R.id.btn_change_activity);
}

private void setEvent() {
    Log.i("Activity A", "setEvent()");
    mBtnChangeActivity.setOnClickListener(this);
}

@Override
protected void onStart() {
    super.onStart();
    Log.i("Activity A", "onStart");
}

@Override
protected void onResume() {
    super.onResume();
    Log.i("Activity A", "onResume");
}

@Override
protected void onPause() {
    super.onPause();
    Log.i("Activity A", "onPause");
}

@Override
protected void onStop() {
    super.onStop();
    Log.i("Activity A", "onStop");
}

@Override
protected void onDestroy() {
    super.onDestroy();
    Log.i("Activity A", "onDestroy");
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
    case R.id.btn_change_activity:
        Intent activityB = new Intent(this, ActivityB.class);
        startActivity(activityB);
        break;
    default:
        break;
    }
}

这里是 B 活动。请按照我的代码注释进行操作。

public class ActivityB extends Activity implements OnClickListener {

// button
private Button mBtnChangeActivity;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_a);
    initialize();
    setEvent();
    // if call finish() here, activityA will don't stop, just pause
    // Activity A will call onStop() when Activity B call onStart() method
    finish();
}

private void initialize() {
    Log.i("Activity B", "Initialize()");
    mBtnChangeActivity = (Button) findViewById(R.id.btn_change_activity);
}

private void setEvent() {
    Log.i("Activity B", "setEvent()");
    mBtnChangeActivity.setOnClickListener(this);
}

@Override
protected void onStart() {
    super.onStart();
    Log.i("Activity B", "onStart");
}

@Override
protected void onResume() {
    super.onResume();
    Log.i("Activity B", "onResume");
}


@Override
public void onClick(View v) {
    switch (v.getId()) {
    case R.id.btn_change_activity:
        finish();
        break;
    default:
        break;
    }
}
}

我希望这很清楚


总是,尽力解释让人理解 - Alexander Zaldostanov

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