"Don't keep activities" 和配置更改有什么区别?
What is the difference between "Don't keep activities" and a Configuration change?
我正在使用视图模型架构组件来处理 UI 状态并包含业务逻辑。众所周知,它在配置更改后仍然存在,但是当在开发人员选项中打开“不保留活动”选项时,将创建一个新的视图模型实例。 activity onDestroy 在这两种情况下都会被调用,那么两者之间有什么区别?
我在 View Model 中维护一个状态机并在恢复它时遇到问题,因为 View Model 无法生存。我不能使用实例状态,因为它有复杂的对象。
以下日志来自我尝试过的示例项目。这有一个 Activity TestActivity
包含一个片段 TestFragment
,并且 TestFragment
包含两个片段 TestStateAFragment
和 TestStateBFragment
TestActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
if(savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.container_fragment_test, TestFragment())
.commitAllowingStateLoss()
}
}
TestFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Timber.i("onViewCreated")
super.onViewCreated(view, savedInstanceState)
if(savedInstanceState == null) {
childFragmentManager.beginTransaction()
.add(R.id.container_state_a, TestStateAFragment.newInstance())
.commitAllowingStateLoss()
childFragmentManager.beginTransaction()
.add(R.id.container_state_b, TestStateBFragment.newInstance())
.commitAllowingStateLoss()
}
}
TestStateAFragment.kt
private val compositeDisposable: CompositeDisposable = CompositeDisposable()
private lateinit var viewModel : TestStateAViewModel
override fun onCreate(savedInstanceState: Bundle?) {
Timber.i("onCreate")
super.onCreate(savedInstanceState)
viewModel = ViewModelProviders.of(this, TestStateAViewModelFactory())
.get(TestStateAViewModel::class.java)
Timber.i(viewModel.toString())
}
屏幕旋转:
(TestStateAFragment.kt:101)#onPause: onPause
(TestStateBFragment.kt:66)#onPause: onPause
(TestFragment.kt:72)#onPause: onPause
(TestActivity.kt:45)#onPause: onPause
(TestStateAFragment.kt:105)#onStop: onStop
(TestStateBFragment.kt:70)#onStop: onStop
(TestFragment.kt:76)#onStop: onStop
(TestActivity.kt:50)#onStop: onStop
(TestActivity.kt:23)#onSaveInstanceState: onSaveInstanceState
(TestFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestStateAFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestActivity.kt:54)#onDestroy: onDestroy
(TestStateAFragment.kt:110)#onDestroyView: onDestroyView
(TestStateBFragment.kt:75)#onDestroyView: onDestroyView
(TestFragment.kt:81)#onDestroyView: onDestroyView
(TestStateAFragment.kt:115)#onDestroy: onDestroy
(TestStateBFragment.kt:80)#onDestroy: onDestroy
(TestFragment.kt:86)#onDestroy: onDestroy
(TestFragment.kt:17)#onAttach: onAttach
(TestFragment.kt:18)#onAttach: TestFragment{984b690 (625e084e-68d8-46d6-9527-dfe2694fa5c1) id=0x7f07004c}
(TestFragment.kt:23)#onCreate: onCreate
(TestStateAFragment.kt:30)#onAttach: onAttach
(TestStateAFragment.kt:31)#onAttach: TestStateAFragment{1ff9e9a (f73d9a4a-4fb0-4e1c-b6b0-220941525ae2) id=0x7f07004d}
(TestStateAFragment.kt:39)#onCreate: onCreate
(TestStateAFragment.kt:44)#onCreate: com.example.lifecycleviewmodel.fragment.states.a.TestStateAViewModel@afc805d
(TestStateBFragment.kt:27)#onAttach: onAttach
(TestStateBFragment.kt:28)#onAttach: TestStateBFragment{908b1a7 (a5fa2bce-9b3b-4474-ae2a-0a891f289f65) id=0x7f07004e}
(TestStateBFragment.kt:33)#onCreate: onCreate
(TestActivity.kt:34)#onStart: onStart
(TestFragment.kt:34)#onCreateView: onCreateView
(TestFragment.kt:40)#onViewCreated: onViewCreated
(TestStateAFragment.kt:67)#onCreateView: onCreateView
(TestStateAFragment.kt:73)#onViewCreated: onViewCreated
(TestStateBFragment.kt:44)#onCreateView: onCreateView
(TestStateBFragment.kt:50)#onViewCreated: onViewCreated
(TestFragment.kt:61)#onStart: onStart
(TestStateAFragment.kt:90)#onStart: onStart
(TestStateBFragment.kt:55)#onStart: onStart
(TestActivity.kt:40)#onResume: onResume
(TestFragment.kt:66)#onResume: onResume
(TestStateAFragment.kt:95)#onResume: onResume
(TestStateBFragment.kt:60)#onResume: onResume
不要停止活动:
(TestStateAFragment.kt:101)#onPause: onPause
(TestStateBFragment.kt:66)#onPause: onPause
(TestFragment.kt:72)#onPause: onPause
(TestActivity.kt:45)#onPause: onPause
(TestStateAFragment.kt:105)#onStop: onStop
(TestStateBFragment.kt:70)#onStop: onStop
(TestFragment.kt:76)#onStop: onStop
(TestActivity.kt:50)#onStop: onStop
(TestActivity.kt:23)#onSaveInstanceState: onSaveInstanceState
(TestFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestStateAFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestActivity.kt:30)#onRestart: onRestart
(TestActivity.kt:34)#onStart: onStart
(TestFragment.kt:61)#onStart: onStart
(TestStateAFragment.kt:90)#onStart: onStart
(TestStateBFragment.kt:55)#onStart: onStart
(TestActivity.kt:40)#onResume: onResume
(TestFragment.kt:66)#onResume: onResume
(TestStateAFragment.kt:95)#onResume: onResume
(TestStateBFragment.kt:60)#onResume: onResume
(TestStateAFragment.kt:101)#onPause: onPause
(TestStateBFragment.kt:66)#onPause: onPause
(TestFragment.kt:72)#onPause: onPause
(TestActivity.kt:45)#onPause: onPause
(TestStateAFragment.kt:105)#onStop: onStop
(TestStateBFragment.kt:70)#onStop: onStop
(TestFragment.kt:76)#onStop: onStop
(TestActivity.kt:50)#onStop: onStop
(TestActivity.kt:23)#onSaveInstanceState: onSaveInstanceState
(TestFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestStateAFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
不要保持活动开启:
(TestStateAFragment.kt:101)#onPause: onPause
(TestStateBFragment.kt:66)#onPause: onPause
(TestFragment.kt:72)#onPause: onPause
(TestActivity.kt:45)#onPause: onPause
(TestStateAFragment.kt:105)#onStop: onStop
(TestStateBFragment.kt:70)#onStop: onStop
(TestFragment.kt:76)#onStop: onStop
(TestActivity.kt:50)#onStop: onStop
(TestActivity.kt:23)#onSaveInstanceState: onSaveInstanceState
(TestFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestStateAFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestActivity.kt:54)#onDestroy: onDestroy
(TestStateAFragment.kt:110)#onDestroyView: onDestroyView
(TestStateBFragment.kt:75)#onDestroyView: onDestroyView
(TestFragment.kt:81)#onDestroyView: onDestroyView
(TestStateAFragment.kt:115)#onDestroy: onDestroy
(TestStateBFragment.kt:80)#onDestroy: onDestroy
(TestFragment.kt:86)#onDestroy: onDestroy
2019-09-18 20:30:10.503 31473-31473/com.example.lifecycleviewmodel W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@d382041
(TestFragment.kt:17)#onAttach: onAttach
(TestFragment.kt:18)#onAttach: TestFragment{544b1c5 (625e084e-68d8-46d6-9527-dfe2694fa5c1) id=0x7f07004c}
(TestFragment.kt:23)#onCreate: onCreate
(TestStateAFragment.kt:30)#onAttach: onAttach
(TestStateAFragment.kt:31)#onAttach: TestStateAFragment{ea5f827 (f73d9a4a-4fb0-4e1c-b6b0-220941525ae2) id=0x7f07004d}
(TestStateAFragment.kt:39)#onCreate: onCreate
(TestStateAFragment.kt:44)#onCreate: com.example.lifecycleviewmodel.fragment.states.a.TestStateAViewModel@fa43f72
(TestStateBFragment.kt:27)#onAttach: onAttach
(TestStateBFragment.kt:28)#onAttach: TestStateBFragment{f66bb79 (a5fa2bce-9b3b-4474-ae2a-0a891f289f65) id=0x7f07004e}
(TestStateBFragment.kt:33)#onCreate: onCreate
(TestActivity.kt:34)#onStart: onStart
(TestFragment.kt:34)#onCreateView: onCreateView
(TestFragment.kt:40)#onViewCreated: onViewCreated
(TestStateAFragment.kt:67)#onCreateView: onCreateView
(TestStateAFragment.kt:73)#onViewCreated: onViewCreated
(TestStateBFragment.kt:44)#onCreateView: onCreateView
(TestStateBFragment.kt:50)#onViewCreated: onViewCreated
(TestFragment.kt:61)#onStart: onStart
(TestStateAFragment.kt:90)#onStart: onStart
(TestStateBFragment.kt:55)#onStart: onStart
(TestActivity.kt:40)#onResume: onResume
(TestFragment.kt:66)#onResume: onResume
(TestStateAFragment.kt:95)#onResume: onResume
(TestStateBFragment.kt:60)#onResume: onResume
那么这两种情况究竟有何不同,有没有办法确定发生了哪一种情况?
当发生 配置更改 时,Android 框架将在您的 Activity
上调用 onRetainNonConfigurationInstance()
。您可以 return 任何您想要的对象。然后 Android 将销毁您的 Activity
并立即创建一个新实例。在新实例的 onCreate()
中,您可以调用 getLastNonConfigurationInstance()
。如果 Activity
由于配置更改而重新创建,您从 onRetainNonConfigurationInstance()
编辑的对象将在此处 return 编辑。否则调用returns null
。在这种情况下,您可以知道您的 Activity
何时因配置更改而重新创建,以及何时因其他原因(重新)启动。
开发者选项 "Don't keep activities" 不是您通常需要处理的事情,因为普通用户永远不应该启用它。您可以将它用于测试目的,以确保您的 Activity
在 Android 决定将其关闭的情况下正确恢复。
实际上,Android 通常不会终止个人活动。如果 Android 需要从后台应用程序 恢复资源,它通常会终止整个 OS 进程 。但是,我最近在某些设备上看到某些情况,当应用程序处于后台时,Android 确实会终止个别活动。当用户随后 return 访问应用程序时,Android 将重新创建 Activity
。在这种情况下,您将从 getLastNonConfigurationInstance()
得到 null
returned,但您会在 onCreate()
调用中得到一个非空的 Bundle
,并且您还会得到onRestoreInstanceState()
中的非空 Bundle
。所以你应该能够区分:
Activity
第一次创建
Activity
配置更改后创建的实例
Activity
实例在 Android 将其关闭并由用户 return 编辑后重新创建
我不太确定你的要求,但这些信息应该有所帮助。
ViewModel 在配置更改后仍然存在,因为 FragmentActivity 在 onRetainNonConfigurationInstance
期间存储它,它在 Activity 的配置更改过程中被调用。我觉得开启"do not keep activities"模式,或者Activity被Android系统回收的时候,都不属于配置变化的过程。因此 onRetainNonConfigurationInstance
将不会被调用,并且 ViewModel 在 Activity 重新创建后将无法生存。
我正在使用视图模型架构组件来处理 UI 状态并包含业务逻辑。众所周知,它在配置更改后仍然存在,但是当在开发人员选项中打开“不保留活动”选项时,将创建一个新的视图模型实例。 activity onDestroy 在这两种情况下都会被调用,那么两者之间有什么区别?
我在 View Model 中维护一个状态机并在恢复它时遇到问题,因为 View Model 无法生存。我不能使用实例状态,因为它有复杂的对象。
以下日志来自我尝试过的示例项目。这有一个 Activity TestActivity
包含一个片段 TestFragment
,并且 TestFragment
包含两个片段 TestStateAFragment
和 TestStateBFragment
TestActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
if(savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.container_fragment_test, TestFragment())
.commitAllowingStateLoss()
}
}
TestFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Timber.i("onViewCreated")
super.onViewCreated(view, savedInstanceState)
if(savedInstanceState == null) {
childFragmentManager.beginTransaction()
.add(R.id.container_state_a, TestStateAFragment.newInstance())
.commitAllowingStateLoss()
childFragmentManager.beginTransaction()
.add(R.id.container_state_b, TestStateBFragment.newInstance())
.commitAllowingStateLoss()
}
}
TestStateAFragment.kt
private val compositeDisposable: CompositeDisposable = CompositeDisposable()
private lateinit var viewModel : TestStateAViewModel
override fun onCreate(savedInstanceState: Bundle?) {
Timber.i("onCreate")
super.onCreate(savedInstanceState)
viewModel = ViewModelProviders.of(this, TestStateAViewModelFactory())
.get(TestStateAViewModel::class.java)
Timber.i(viewModel.toString())
}
屏幕旋转:
(TestStateAFragment.kt:101)#onPause: onPause
(TestStateBFragment.kt:66)#onPause: onPause
(TestFragment.kt:72)#onPause: onPause
(TestActivity.kt:45)#onPause: onPause
(TestStateAFragment.kt:105)#onStop: onStop
(TestStateBFragment.kt:70)#onStop: onStop
(TestFragment.kt:76)#onStop: onStop
(TestActivity.kt:50)#onStop: onStop
(TestActivity.kt:23)#onSaveInstanceState: onSaveInstanceState
(TestFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestStateAFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestActivity.kt:54)#onDestroy: onDestroy
(TestStateAFragment.kt:110)#onDestroyView: onDestroyView
(TestStateBFragment.kt:75)#onDestroyView: onDestroyView
(TestFragment.kt:81)#onDestroyView: onDestroyView
(TestStateAFragment.kt:115)#onDestroy: onDestroy
(TestStateBFragment.kt:80)#onDestroy: onDestroy
(TestFragment.kt:86)#onDestroy: onDestroy
(TestFragment.kt:17)#onAttach: onAttach
(TestFragment.kt:18)#onAttach: TestFragment{984b690 (625e084e-68d8-46d6-9527-dfe2694fa5c1) id=0x7f07004c}
(TestFragment.kt:23)#onCreate: onCreate
(TestStateAFragment.kt:30)#onAttach: onAttach
(TestStateAFragment.kt:31)#onAttach: TestStateAFragment{1ff9e9a (f73d9a4a-4fb0-4e1c-b6b0-220941525ae2) id=0x7f07004d}
(TestStateAFragment.kt:39)#onCreate: onCreate
(TestStateAFragment.kt:44)#onCreate: com.example.lifecycleviewmodel.fragment.states.a.TestStateAViewModel@afc805d
(TestStateBFragment.kt:27)#onAttach: onAttach
(TestStateBFragment.kt:28)#onAttach: TestStateBFragment{908b1a7 (a5fa2bce-9b3b-4474-ae2a-0a891f289f65) id=0x7f07004e}
(TestStateBFragment.kt:33)#onCreate: onCreate
(TestActivity.kt:34)#onStart: onStart
(TestFragment.kt:34)#onCreateView: onCreateView
(TestFragment.kt:40)#onViewCreated: onViewCreated
(TestStateAFragment.kt:67)#onCreateView: onCreateView
(TestStateAFragment.kt:73)#onViewCreated: onViewCreated
(TestStateBFragment.kt:44)#onCreateView: onCreateView
(TestStateBFragment.kt:50)#onViewCreated: onViewCreated
(TestFragment.kt:61)#onStart: onStart
(TestStateAFragment.kt:90)#onStart: onStart
(TestStateBFragment.kt:55)#onStart: onStart
(TestActivity.kt:40)#onResume: onResume
(TestFragment.kt:66)#onResume: onResume
(TestStateAFragment.kt:95)#onResume: onResume
(TestStateBFragment.kt:60)#onResume: onResume
不要停止活动:
(TestStateAFragment.kt:101)#onPause: onPause
(TestStateBFragment.kt:66)#onPause: onPause
(TestFragment.kt:72)#onPause: onPause
(TestActivity.kt:45)#onPause: onPause
(TestStateAFragment.kt:105)#onStop: onStop
(TestStateBFragment.kt:70)#onStop: onStop
(TestFragment.kt:76)#onStop: onStop
(TestActivity.kt:50)#onStop: onStop
(TestActivity.kt:23)#onSaveInstanceState: onSaveInstanceState
(TestFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestStateAFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestActivity.kt:30)#onRestart: onRestart
(TestActivity.kt:34)#onStart: onStart
(TestFragment.kt:61)#onStart: onStart
(TestStateAFragment.kt:90)#onStart: onStart
(TestStateBFragment.kt:55)#onStart: onStart
(TestActivity.kt:40)#onResume: onResume
(TestFragment.kt:66)#onResume: onResume
(TestStateAFragment.kt:95)#onResume: onResume
(TestStateBFragment.kt:60)#onResume: onResume
(TestStateAFragment.kt:101)#onPause: onPause
(TestStateBFragment.kt:66)#onPause: onPause
(TestFragment.kt:72)#onPause: onPause
(TestActivity.kt:45)#onPause: onPause
(TestStateAFragment.kt:105)#onStop: onStop
(TestStateBFragment.kt:70)#onStop: onStop
(TestFragment.kt:76)#onStop: onStop
(TestActivity.kt:50)#onStop: onStop
(TestActivity.kt:23)#onSaveInstanceState: onSaveInstanceState
(TestFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestStateAFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
不要保持活动开启:
(TestStateAFragment.kt:101)#onPause: onPause
(TestStateBFragment.kt:66)#onPause: onPause
(TestFragment.kt:72)#onPause: onPause
(TestActivity.kt:45)#onPause: onPause
(TestStateAFragment.kt:105)#onStop: onStop
(TestStateBFragment.kt:70)#onStop: onStop
(TestFragment.kt:76)#onStop: onStop
(TestActivity.kt:50)#onStop: onStop
(TestActivity.kt:23)#onSaveInstanceState: onSaveInstanceState
(TestFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestStateAFragment.kt:55)#onSaveInstanceState: onSaveInstanceState
(TestActivity.kt:54)#onDestroy: onDestroy
(TestStateAFragment.kt:110)#onDestroyView: onDestroyView
(TestStateBFragment.kt:75)#onDestroyView: onDestroyView
(TestFragment.kt:81)#onDestroyView: onDestroyView
(TestStateAFragment.kt:115)#onDestroy: onDestroy
(TestStateBFragment.kt:80)#onDestroy: onDestroy
(TestFragment.kt:86)#onDestroy: onDestroy
2019-09-18 20:30:10.503 31473-31473/com.example.lifecycleviewmodel W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@d382041
(TestFragment.kt:17)#onAttach: onAttach
(TestFragment.kt:18)#onAttach: TestFragment{544b1c5 (625e084e-68d8-46d6-9527-dfe2694fa5c1) id=0x7f07004c}
(TestFragment.kt:23)#onCreate: onCreate
(TestStateAFragment.kt:30)#onAttach: onAttach
(TestStateAFragment.kt:31)#onAttach: TestStateAFragment{ea5f827 (f73d9a4a-4fb0-4e1c-b6b0-220941525ae2) id=0x7f07004d}
(TestStateAFragment.kt:39)#onCreate: onCreate
(TestStateAFragment.kt:44)#onCreate: com.example.lifecycleviewmodel.fragment.states.a.TestStateAViewModel@fa43f72
(TestStateBFragment.kt:27)#onAttach: onAttach
(TestStateBFragment.kt:28)#onAttach: TestStateBFragment{f66bb79 (a5fa2bce-9b3b-4474-ae2a-0a891f289f65) id=0x7f07004e}
(TestStateBFragment.kt:33)#onCreate: onCreate
(TestActivity.kt:34)#onStart: onStart
(TestFragment.kt:34)#onCreateView: onCreateView
(TestFragment.kt:40)#onViewCreated: onViewCreated
(TestStateAFragment.kt:67)#onCreateView: onCreateView
(TestStateAFragment.kt:73)#onViewCreated: onViewCreated
(TestStateBFragment.kt:44)#onCreateView: onCreateView
(TestStateBFragment.kt:50)#onViewCreated: onViewCreated
(TestFragment.kt:61)#onStart: onStart
(TestStateAFragment.kt:90)#onStart: onStart
(TestStateBFragment.kt:55)#onStart: onStart
(TestActivity.kt:40)#onResume: onResume
(TestFragment.kt:66)#onResume: onResume
(TestStateAFragment.kt:95)#onResume: onResume
(TestStateBFragment.kt:60)#onResume: onResume
那么这两种情况究竟有何不同,有没有办法确定发生了哪一种情况?
当发生 配置更改 时,Android 框架将在您的 Activity
上调用 onRetainNonConfigurationInstance()
。您可以 return 任何您想要的对象。然后 Android 将销毁您的 Activity
并立即创建一个新实例。在新实例的 onCreate()
中,您可以调用 getLastNonConfigurationInstance()
。如果 Activity
由于配置更改而重新创建,您从 onRetainNonConfigurationInstance()
编辑的对象将在此处 return 编辑。否则调用returns null
。在这种情况下,您可以知道您的 Activity
何时因配置更改而重新创建,以及何时因其他原因(重新)启动。
开发者选项 "Don't keep activities" 不是您通常需要处理的事情,因为普通用户永远不应该启用它。您可以将它用于测试目的,以确保您的 Activity
在 Android 决定将其关闭的情况下正确恢复。
实际上,Android 通常不会终止个人活动。如果 Android 需要从后台应用程序 恢复资源,它通常会终止整个 OS 进程 。但是,我最近在某些设备上看到某些情况,当应用程序处于后台时,Android 确实会终止个别活动。当用户随后 return 访问应用程序时,Android 将重新创建 Activity
。在这种情况下,您将从 getLastNonConfigurationInstance()
得到 null
returned,但您会在 onCreate()
调用中得到一个非空的 Bundle
,并且您还会得到onRestoreInstanceState()
中的非空 Bundle
。所以你应该能够区分:
Activity
第一次创建Activity
配置更改后创建的实例Activity
实例在 Android 将其关闭并由用户 return 编辑后重新创建
我不太确定你的要求,但这些信息应该有所帮助。
ViewModel 在配置更改后仍然存在,因为 FragmentActivity 在 onRetainNonConfigurationInstance
期间存储它,它在 Activity 的配置更改过程中被调用。我觉得开启"do not keep activities"模式,或者Activity被Android系统回收的时候,都不属于配置变化的过程。因此 onRetainNonConfigurationInstance
将不会被调用,并且 ViewModel 在 Activity 重新创建后将无法生存。