用户交互能否在 OnResume 完成之前触发事件?
Can a user interaction trigger events before OnResume has finished?
在我的一个 Fragment
中,我正在为 onResume()
中的 EditText
注册一个 OnFocusChangeListener
:
override fun onResume() {
super.onResume()
editText.setOnFocusChangeListener {
// do something here
}
}
我在 onResume()
中注册侦听器,因为如果我在较早的生命周期方法中设置它,它会在每次配置更改时触发。在 onResume()
中设置它可确保在注册侦听器之前已恢复配置更改之前存在的焦点,因此侦听器不会在配置更改/焦点恢复后自动触发。
现在我担心我可能注册这个侦听器太晚了。所以我的问题是:在执行 onResume()
之前或期间,用户交互是否已经导致对元素的关注? (这意味着,我会松开这个焦点事件,因为我在 onResume()
期间设置监听器)。或者更笼统:在执行 onResume()
时是否已经可以进行用户交互?片段 documentation 说到 onResume()
:
Called when the fragment is visible to the user and actively running.
"visible to the user"的意思很清楚,但是"actively running"到底是什么意思呢?这是否已经意味着接受用户输入?还是在 onResume()
完成后首先接受用户输入?
查看 FragmentManager
源代码,performResume
触发 onResume
的调用在片段启动后立即执行(并调用 onStart
):
https://android.googlesource.com/platform/frameworks/support/+/84448d71fda0a24ba5d60fe9368ac47b97564c88/fragment/src/main/java/androidx/fragment/app/FragmentManagerImpl.java#926
用户交互需要启动片段,onStart
和 onResume
调用之间不会发生交互,因为它们只能在同一个主线程上执行。
所以,是的,在 onResume
之前无法进行用户输入。
焦点恢复在 Activity 的 onRestoreInstanceState()
, which is done separately from when Fragment's restore their own View's state (that would be in the Fragment's onViewStateRestored()
) 中完成。
根据 onRestoreInstanceState()
文档,它在 Activity 的 onStart()
和 onPostCreate()
之间调用(运行 在 onResume()
和 onPostResume()
- onPostResume()
是片段获得 onResume()
回调的时间)。
这意味着您是正确的,因为在 onResume()
之前的片段级别没有可用的回调,其中在调用该方法之前正确设置了焦点。
也就是说,是的,用户可以在 Fragment 达到恢复状态之前与它进行交互。例如,ViewPager2
(as well as ViewPager 1 when using BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
) keep the non-selected fragments (i.e., those not in the middle of the screen) in the STARTED
state. Through the power of multi-touch, users could drag a page over slightly and then use another finger to tap on a view that is partially visible. You'd see the same behavior if you use setMaxLifecycle()
和 Lifecycle.State.STARTED
你自己(这就是那些在幕后所做的事情)——片段是可交互的,但不是 RESUMED。
然而,在大多数一般情况下,如果您不使用上述任何 API,片段生命周期通常与 Activity 生命周期相匹配。 activity,根据 ActivityThread source code,运行 其更新全部采用相同的 handleStartActivity()
方法。
需要注意的是,每次 activity 被销毁时,当视图被移除时,你会得到一个回调到你的 OnFocusChangeListener
和 false
的 hasFocus
来自 Activity(它总是失去 View 的焦点)。这发生在状态被保存之后,视图的焦点状态实际上并没有丢失,这只是您已经需要在回调中处理的事情,通常通过检查 isStateSaved()
and ignoring focus loss after the state is saved and checking isRemoving()
如果您手动删除/替换片段(即,通过执行 replace()
操作)。
鉴于您已经必须在侦听器中具有逻辑以避免处理 hasFocus
错误事件 post 破坏,处理获得焦点的 100% 正确情况将涉及保存您自己的在您保存的实例状态中关注状态(即特定视图的 true 或 false),并且如果 hasFocus
正在从您已经保存的内容更改,则仅 运行 调整您的逻辑。这意味着您将在 Fragment 的生命周期早期恢复您保存的实例状态(例如,在 Fragment 提供的 onViewStateRestored()
方法中)并在那里添加您的侦听器。然后,您的逻辑可以安全地忽略具有相同焦点的回调:
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
// Restore your member variable of focus
focused = savedInstanceState?.getBoolean("HAS_FOCUS", false) ?: false
editText.setOnFocusChangeListener { _, hasFocus ->
if (focused == hasFocus) {
// ignore
return
}
focused = hasFocus
if (hasFocus) {
// We gained focus
} else if (!isStateSaved() && !isRemoving()) {
// We lost focus
}
}
}
在我的一个 Fragment
中,我正在为 onResume()
中的 EditText
注册一个 OnFocusChangeListener
:
override fun onResume() {
super.onResume()
editText.setOnFocusChangeListener {
// do something here
}
}
我在 onResume()
中注册侦听器,因为如果我在较早的生命周期方法中设置它,它会在每次配置更改时触发。在 onResume()
中设置它可确保在注册侦听器之前已恢复配置更改之前存在的焦点,因此侦听器不会在配置更改/焦点恢复后自动触发。
现在我担心我可能注册这个侦听器太晚了。所以我的问题是:在执行 onResume()
之前或期间,用户交互是否已经导致对元素的关注? (这意味着,我会松开这个焦点事件,因为我在 onResume()
期间设置监听器)。或者更笼统:在执行 onResume()
时是否已经可以进行用户交互?片段 documentation 说到 onResume()
:
Called when the fragment is visible to the user and actively running.
"visible to the user"的意思很清楚,但是"actively running"到底是什么意思呢?这是否已经意味着接受用户输入?还是在 onResume()
完成后首先接受用户输入?
查看 FragmentManager
源代码,performResume
触发 onResume
的调用在片段启动后立即执行(并调用 onStart
):
https://android.googlesource.com/platform/frameworks/support/+/84448d71fda0a24ba5d60fe9368ac47b97564c88/fragment/src/main/java/androidx/fragment/app/FragmentManagerImpl.java#926
用户交互需要启动片段,onStart
和 onResume
调用之间不会发生交互,因为它们只能在同一个主线程上执行。
所以,是的,在 onResume
之前无法进行用户输入。
焦点恢复在 Activity 的 onRestoreInstanceState()
, which is done separately from when Fragment's restore their own View's state (that would be in the Fragment's onViewStateRestored()
) 中完成。
根据 onRestoreInstanceState()
文档,它在 Activity 的 onStart()
和 onPostCreate()
之间调用(运行 在 onResume()
和 onPostResume()
- onPostResume()
是片段获得 onResume()
回调的时间)。
这意味着您是正确的,因为在 onResume()
之前的片段级别没有可用的回调,其中在调用该方法之前正确设置了焦点。
也就是说,是的,用户可以在 Fragment 达到恢复状态之前与它进行交互。例如,ViewPager2
(as well as ViewPager 1 when using BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
) keep the non-selected fragments (i.e., those not in the middle of the screen) in the STARTED
state. Through the power of multi-touch, users could drag a page over slightly and then use another finger to tap on a view that is partially visible. You'd see the same behavior if you use setMaxLifecycle()
和 Lifecycle.State.STARTED
你自己(这就是那些在幕后所做的事情)——片段是可交互的,但不是 RESUMED。
然而,在大多数一般情况下,如果您不使用上述任何 API,片段生命周期通常与 Activity 生命周期相匹配。 activity,根据 ActivityThread source code,运行 其更新全部采用相同的 handleStartActivity()
方法。
需要注意的是,每次 activity 被销毁时,当视图被移除时,你会得到一个回调到你的 OnFocusChangeListener
和 false
的 hasFocus
来自 Activity(它总是失去 View 的焦点)。这发生在状态被保存之后,视图的焦点状态实际上并没有丢失,这只是您已经需要在回调中处理的事情,通常通过检查 isStateSaved()
and ignoring focus loss after the state is saved and checking isRemoving()
如果您手动删除/替换片段(即,通过执行 replace()
操作)。
鉴于您已经必须在侦听器中具有逻辑以避免处理 hasFocus
错误事件 post 破坏,处理获得焦点的 100% 正确情况将涉及保存您自己的在您保存的实例状态中关注状态(即特定视图的 true 或 false),并且如果 hasFocus
正在从您已经保存的内容更改,则仅 运行 调整您的逻辑。这意味着您将在 Fragment 的生命周期早期恢复您保存的实例状态(例如,在 Fragment 提供的 onViewStateRestored()
方法中)并在那里添加您的侦听器。然后,您的逻辑可以安全地忽略具有相同焦点的回调:
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
// Restore your member variable of focus
focused = savedInstanceState?.getBoolean("HAS_FOCUS", false) ?: false
editText.setOnFocusChangeListener { _, hasFocus ->
if (focused == hasFocus) {
// ignore
return
}
focused = hasFocus
if (hasFocus) {
// We gained focus
} else if (!isStateSaved() && !isRemoving()) {
// We lost focus
}
}
}