في معظم الحالات ، لا يلزم إجراء تسلسل في 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