TL; DR:在大多数应用程序中,做出明确的,有意识的体系结构决策是有意义的,即在发生进程死亡的情况下,应用程序仅从头开始重新启动而无需尝试恢复状态。并且在这种情况下Serializable
,不需要Parcelable
其他Bundle
。
如果应用程序的至少一项活动在onStart()
和之间onStop()
,那么可以确保该活动以及活动所在的过程是安全的。在其他情况下,操作系统可以随时终止应用程序进程。
我不必在真实应用程序中实现对进程终止的透明(即对用户不可见)处理。但这似乎很可行,概述了一个工作示例:https : //github.com/mychka/resurrection。
这个想法是在每个活动中onSaveInstanceState()
保存应用程序的整个状态onCreate()
,如果该进程被终止,请还原:
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ResurrectionApp.ensureState(savedInstanceState)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
ResurrectionApp.STATE.save(outState)
}
}
为了模拟进程的终止,可以最小化应用程序并使用以下命令
adb shell am kill org.resurrection
如果我们决定处理该过程的终止,那么可以注意到以下开销。
代码复杂化。
- , , , . , , - . - : , , .
Serializable
/Parcelable
.- — , . ,
loading == true
. , , loading
false
. TCP-, . - ,
Activity#onCreate()
— , — .
, , , . , , , - .
Activity#onSaveInstanceState()
. (, Activity#isChangingConfigurations == true
, , .) , , - .
. 1, . / .
. , , , , , - .
, , : , . , , , .
, . , , foreground . , .
( ) , , .
. (02.03.2020) : Facebook, Twitter, WhatsApp, Chrome, Gmail, Yandex.Maps. : Yandex.Navigator, YouTube, -, Skype.
, , . , , . : , .
https://github.com/mychka/life-from-scratch
BaseActivity
. LoginActivity
. "NEXT". DashboardActivity
. .
adb shell am kill org.lifefromscratch
. , DashboardActivity
LoginActivity#loginShownAt
, .
. , . , :
abstract class BaseActivity : AppCompatActivity() {
companion object {
init {
if (!appStartedNormally) {
APP.startActivity(
APP.getPackageManager().getLaunchIntentForPackage(
APP.getPackageName()
)
);
System.exit(0)
}
}
}
}
. , -.
. , .
class BinderReference<T>(val value: T?) : Binder()
Parcel
. ,
class MyNonSerializableData(val os: OutputStream)
val parcel: Parcel = Parcel.obtain()
val obj = MyNonSerializableData(ByteArrayOutputStream())
parcel.writeStrongBinder(BinderReference(obj))
parcel.setDataPosition(0)
val obj2 = (parcel.readStrongBinder() as BinderReference<*>).value
assert(obj === obj2)
android.os.Binder
https://habr.com/ru/post/274635/
. . , . :
const val DEFAULT_BUNDLE_KEY = "com.example.DEFAULT_BUNDLE_KEY.cr5?Yq+&Jr@rnH5j"
val Any?.bundle: Bundle?
get() = if (this == null) null else Bundle().also { it.putBinder(DEFAULT_BUNDLE_KEY, BinderReference(this)) }
inline fun <reified T> Bundle?.value(): T =
this?.getBinder(DEFAULT_BUNDLE_KEY)?.let {
if (it is BinderReference<*>) it.value as T else null
} as T
inline fun <reified Arg> Fragment.defaultArg() = lazy<Arg>(LazyThreadSafetyMode.NONE) {
arguments.value()
}
. :
findNavController(R.id.nav_host_fragment).navigate(
R.id.bbbFragment,
MyNonSerializableData(ByteArrayOutputStream()).bundle
)
val data: MyNonSerializableData by defaultArg()
— androidx.lifecycle.ViewModel
. , , destroy , configuration change, https://developer.android.com/reference/androidx/activity/ComponentActivity.html#onRetainCustomNonConfigurationInstance()
, , , . ViewModel
.
BinderReference
, androidx.lifecycle.ViewModel
, onSaveInstanceState(outState)
/onCreate(savedInstanceState)
. view model .
UPD: kamer Dimezis , , 2.3 (API 9). . (, finish()
), configuration change. :
https://stackoverflow.com/questions/7536988/android-app-out-of-memory-issues-tried-everything-and-still-at-a-loss/7576275#7576275
https://stackoverflow.com/questions/11616575/android-not-killing-activities-from-stack-when-memory-is-low/11616829#11616829
:
https://issuetracker.google.com/issues/36934944
可以肯定地说,您需要深入研究Android的源代码。如果存在“不保留活动”选项,则Android内核中有一个代码可以“轻轻地”销毁活动。与调用时相比,很有可能在调用此代码时出现棘手的情况,因此androidx.lifecycle.ViewModel
会导致崩溃onSaveInstanceState()
。但是显然,在现实生活中,androidx.lifecycle.ViewModel
您仍然可以安全地使用它。