Na maioria dos casos, a serialização no Android não é necessária

TL; DR: Na maioria dos aplicativos, faz sentido tomar uma decisão arquitetônica consciente explícita de que, no caso de uma morte no processo, o aplicativo simplesmente reinicia do zero sem tentar restaurar o estado. E, neste caso Serializable, Parcelablee outros Bundlenão são necessários.


Se pelo menos uma atividade de aplicativo estiver entre onStart()e onStop(), é garantido que a atividade e, portanto, o processo em que a atividade vive, são seguros. Em outros casos, o sistema operacional pode interromper o processo de inscrição a qualquer momento.


Não tive que implementar um processamento transparente (ou seja, invisível para o usuário) da morte de um processo em um aplicativo real. Mas parece bastante viável, delineou um exemplo de trabalho: https://github.com/mychka/resurrection .


A idéia é onSaveInstanceState()salvar todo o estado do aplicativo em cada atividade e onCreate(), se o processo foi interrompido, restaure:


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)
    }
}

Para simular uma interrupção do processo, você pode minimizar o aplicativo e usar o comando


adb shell am kill org.resurrection

Se decidirmos lidar com a morte do processo, será possível observar a sobrecarga a seguir.


  1. Código complicação.


    • , , , . , , - . - : , , .
    • 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
Para dizer com certeza, você precisa mergulhar no código fonte do Android. Se houver uma opção "Não manter atividades", existe um código no kernel do Android que pode "suavemente" destruir as atividades. Com uma alta probabilidade, você pode criar um cenário complicado quando esse código é chamado e, consequentemente, androidx.lifecycle.ViewModellevar a uma falha, ao contrário onSaveInstanceState(). Mas na vida real, aparentemente, androidx.lifecycle.ViewModelvocê ainda pode usá-lo com segurança.


All Articles