在大多数情况下,不需要在Android中进行序列化

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

如果我们决定处理该过程的终止,那么可以注意到以下开销。


  1. 代码复杂化。


    • , , , . , , - . - : , , .
    • Serializable/Parcelable.
    • — , . , loading == true . , , loading false. TCP-, .
    • , Activity#onCreate() — , — .

    , , , . , , , - .


  2. Activity#onSaveInstanceState() . (, Activity#isChangingConfigurations == true, , .) , , - .


  3. . 1, . / .


  4. . , , , , , - .
    , , : , . , , , .



, . , , 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仍然可以安全地使用它。


All Articles