活动何时可见?在 onStart() 或 onResume() 之后?
Posted
技术标签:
【中文标题】活动何时可见?在 onStart() 或 onResume() 之后?【英文标题】:When activity will be visible? After onStart() or onResume()? 【发布时间】:2020-11-21 00:04:38 【问题描述】:Docs说:
Activity 的可见生命周期发生在调用
onStart()
到对应调用onStop()
之间。
你也可以在this one看到:
onStart()
调用使活动对用户可见...
所以我认为从onStart()
返回后Activity的UI一定是可见的。
最近为了测试,我在onResume()
中放了一个无限循环,猜想Activity的UI一定是可见的。但是启动Activity的结果是一个没有任何UI的白窗。
所以从onResume()
返回而不是从onStart()
返回后,Activity的UI似乎是可见的。这是真的?如果是,为什么文档会说这样的误导性陈述?
编辑:
你可能会想像 Công Hải says:
我认为文档中提到了窗口可见而不是视图可见。
但我不认为“可见性”是指上面提到的“白窗”;因为如果你在onCreate()
中放置一个无限循环,再次启动 Activity 的结果将是一个白色窗口,而正如文档所说,onCreate()
不在 Activity 的“可见生命周期”中。所以“Activity的可见性”一定是指“白窗”以外的东西。
编辑2
除了官方文档,许多教程都说通过调用 onStart()
可以看到 Activity 并通过调用 onResume()
进行交互。都是未经测试就说错话吗?
【问题讨论】:
我认为文件中提到的窗口可见而不是视图可见。 @CôngHải 请查看我的编辑。 好的,同意你的说法,看别人解释一下 "当活动对用户可见时调用。如果活动进入前台,则调用 onResume(),如果活动隐藏,则调用 onStop()。"在您放置的文档中,我读到它正在“变为”不可见,如果您将循环放入onResume
会发生什么?
@CôngHải 正如我在问题中提到的,在onResume()
中放置无限循环并启动 Activity,会导致冻结的白色窗口。
【参考方案1】:
在onResume()
中设置一个无限循环并不能真正告诉你整个故事。有很多活动排队到主(UI)线程(比如绘制屏幕),因为onResume()
在主(UI)线程上被调用,你阻止android在主(UI)上做任何工作线。这就是您在这种情况下看到白(或黑)屏幕的原因。
为回答您的问题,Activity
将在onResume()
之后显示。
【讨论】:
你说:“在 onResume() 中设置一个无限循环并不能真正告诉你整个故事”。我认为测试活动何时可见就足够了。你同意吗? @您说:“活动将在 onResume() 之后可见”,所以您认为文档在这里具有误导性? 放置一个无限循环无法测试Activity
是否可见。它现在可能是可见的,但是因为你已经阻塞了主(UI)线程,所以什么都不能绘制,所以你实际上看不到Activity
。此测试无效且无定论。
我可以理解您说这些文档具有误导性。不幸的是,许多 Android 文档具有误导性、不正确、令人困惑和/或冲突。很大程度上取决于“可见”的含义。如果您看到一个白色窗口,那么我们可以说Activity
是可见的,因为您不再看到主屏幕。但是,框架仍然需要测量和绘制所有View
s,以便 UI 对用户真正可见。所以这只是“可见”这个词的语义定义问题。【参考方案2】:
仔细查看the docs that you linked。它指出:
如果活动失去焦点但仍呈现给用户,则它是可见的。如果一个新的非全尺寸或透明活动的焦点位于您的活动之上,另一个活动在多窗口模式下具有更高的位置,或者活动本身在当前窗口模式下不可聚焦,则可能是这样。这样的活动是完全活跃的(它维护所有状态和成员信息,并保持连接到窗口管理器)。
如果一个活动被另一个活动完全遮挡,它会被停止或隐藏。它仍然保留所有状态和成员信息,但是,它不再对用户可见,因此它的窗口是隐藏的,并且当其他地方需要内存时,它通常会被系统杀死。
[...]
活动的可见生命周期发生在对 onStart() 的调用与对 onStop() 的相应调用之间。在此期间,用户可以在屏幕上看到活动,尽管它可能不在前台并与用户交互。在这两种方法之间,您可以维护向用户显示活动所需的资源。例如,您可以在 onStart() 中注册 BroadcastReceiver 以监控影响 UI 的更改,并在用户不再看到您正在显示的内容时在 onStop() 中取消注册。 onStart() 和 onStop() 方法可以多次调用,因为活动对用户可见和隐藏。
这清楚地描绘了“可见”的含义:您的活动至少控制了屏幕上显示的部分内容。
通过阻止onResume
,您已阻止您的活动正常启动和/或呈现您的内容,但它仍然对用户可见(白屏)并遮盖了以前可见的活动。
【讨论】:
正如我在问题中提到的“如果你在 onCreate() 中设置一个无限循环,再次启动 Activity 的结果将是一个白色窗口”这意味着 Activity 控制了屏幕的一部分。因此,从您的潜在客户看来,它在onCreate()
中是“可见的”;但它违反了以下声明:“活动的可见生命周期发生在对 onStart() 的调用与对 onStop() 的相应调用之间”。
您说您将循环放在“可见生命周期”内的onResume
中。矛盾在哪里?
刚刚看到您的编辑。好吧,在这里我们必须回到这样一个事实,即这些回调只是由系统调度的钩子。因此,如果您决定阻止这样的回调,则取决于系统如何对此做出反应。简而言之,这种行为是未定义的。系统只是提醒您,您的活动将很快可见。我觉得有趣的是,这就是最终发生的事情。但我不会依赖它或用它来得出更深层次的结论。
顺便说一句,您看到的不仅仅是白屏,而是主题中指定的 windowBackground。【参考方案3】:
请查看活动生命周期。
活动在onResume()
和onPause()
之间可见并正在运行。更多信息请参考this docs。
现在回到为什么你会看到白屏。
视图是异步绘制的——这意味着代码的执行不会等到视图绘制完成。如果在渲染所有视图之前调用 onResume()
并且您的无限循环开始 - 它会消耗所有计算能力并且您的 UI 将不会被渲染。
让我说得更清楚。为什么你问在onResume
中放置无限循环时没有显示视图?你为什么不问为什么即使在onCreate
本身的setContentView
之后出现无限循环,为什么也没有创建视图?
进一步指出您误解的根源——您认为onStart
和onResume
仅在创建视图后才被调用。这不正确。 onStart
和 onResume
甚至可以在视图绘制未完成之前调用。因此,情况可能是您的视图可能存在于内存中但尚未呈现。
还有一点值得注意
-
在
onCreate
中调用setContentView()
不是必须的,你甚至可以在onStart
或onResume
中调用它
如果由于某种原因你想在做某事之前等待一个特定的视图被绘制,你必须在 postRunnable 中运行你的代码
yourView.post(new Runnable(
public void run()
// do your stuff
));
【讨论】:
以上是关于活动何时可见?在 onStart() 或 onResume() 之后?的主要内容,如果未能解决你的问题,请参考以下文章
Android:在活动中 onStart()、onStop()、onDestroy() 的开头或结尾调用 super()?