Dalam kebanyakan kasus, serialisasi di Android tidak diperlukan

TL; DR: Dalam sebagian besar aplikasi, masuk akal untuk membuat keputusan arsitektural sadar yang eksplisit bahwa, jika terjadi proses kematian, aplikasi tersebut hanya restart dari awal tanpa berusaha mengembalikan keadaan. Dan dalam hal ini Serializable, Parcelabledan yang lainnya Bundletidak diperlukan.


Jika setidaknya satu aktivitas aplikasi berada di antara onStart()dan onStop(), maka dijamin aktivitas tersebut, dan oleh karena itu proses di mana aktivitas itu berlangsung, aman. Dalam kasus lain, sistem operasi dapat mematikan proses aplikasi kapan saja.


Saya tidak harus mengimplementasikan proses transparan (yaitu tidak terlihat oleh pengguna) kematian proses dalam aplikasi nyata. Tetapi tampaknya cukup layak, diuraikan contoh yang berfungsi: https://github.com/mychka/resurrection .


Idenya adalah untuk onSaveInstanceState()menyimpan seluruh status aplikasi di setiap aktivitas , dan onCreate(), jika prosesnya dimatikan, pulihkan:


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

Untuk mensimulasikan pembunuhan suatu proses, Anda dapat meminimalkan aplikasi dan menggunakan perintah


adb shell am kill org.resurrection

Jika kita memutuskan untuk menangani kematian proses, maka overhead berikut dapat dicatat.


  1. Komplikasi kode.


    • , , , . , , - . - : , , .
    • 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
Untuk mengatakan dengan pasti, Anda perlu menyelami kode sumber Android. Jika ada opsi "Jangan menyimpan aktivitas", maka ada kode di kernel Android yang dapat "dengan lembut" menghancurkan aktivitas. Dengan probabilitas tinggi, Anda dapat membuat skenario rumit ketika kode ini dipanggil, dan, karenanya, androidx.lifecycle.ViewModelakan menyebabkan crash, tidak seperti onSaveInstanceState(). Namun dalam kehidupan nyata, tampaknya, androidx.lifecycle.ViewModelAnda masih bisa menggunakannya dengan aman.


All Articles