In den meisten FĂ€llen ist eine Serialisierung in Android nicht erforderlich

TL; DR: In den meisten Anwendungen ist es sinnvoll, eine explizite bewusste Architekturentscheidung zu treffen, bei der die Anwendung im Falle eines Prozesstodes einfach von Grund auf neu gestartet wird, ohne zu versuchen, den Status wiederherzustellen. Und in diesem Fall Serializablewerden Parcelableandere Bundlenicht benötigt.


Befindet sich mindestens eine AnwendungsaktivitĂ€t zwischen onStart()und onStop(), ist garantiert, dass die AktivitĂ€t und damit der Prozess, in dem die AktivitĂ€t ausgefĂŒhrt wird, sicher sind. In anderen FĂ€llen kann das Betriebssystem den Anwendungsprozess jederzeit beenden.


Ich musste keine transparente (dh fĂŒr den Benutzer unsichtbare) Verarbeitung des Todes eines Prozesses in einer realen Anwendung implementieren. Aber es scheint durchaus machbar zu sein, skizzierte ein funktionierendes Beispiel: https://github.com/mychka/resurrection .


Die Idee ist, onSaveInstanceState()den gesamten Status der Anwendung in jeder AktivitÀt zu speichern und onCreate(), falls der Prozess abgebrochen wurde, wiederherzustellen:


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

Um das Beenden eines Prozesses zu simulieren, können Sie die Anwendung minimieren und den Befehl verwenden


adb shell am kill org.resurrection

Wenn wir uns entscheiden, den Tod des Prozesses zu behandeln, kann der folgende Aufwand festgestellt werden.


  1. Code-Komplikation.


    • , , , . , , - . - : , , .
    • 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
Um sicher zu sein, mĂŒssen Sie in den Quellcode von Android eintauchen. Wenn es eine Option "AktivitĂ€ten nicht behalten" gibt, gibt es im Android-Kernel einen Code, der AktivitĂ€ten "sanft" zerstören kann. Mit hoher Wahrscheinlichkeit können Sie sich ein schwieriges Szenario einfallen lassen, wenn dieser Code aufgerufen wird, und dementsprechend androidx.lifecycle.ViewModelim Gegensatz zu einem Absturz fĂŒhren onSaveInstanceState(). Aber im wirklichen Leben können Sie es anscheinend androidx.lifecycle.ViewModelimmer noch sicher verwenden.


All Articles