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
إذا قررنا التعامل مع وفاة العملية ، فيمكن ملاحظة النفقات العامة التالية.
تعقيد التعليمات البرمجية.
- , , , . , , - . - : , , .
Serializable
/Parcelable
.- — , . ,
loading == true
. , , loading
false
. TCP-, . - ,
Activity#onCreate()
— , — .
, , , . , , , - .
Activity#onSaveInstanceState()
. (, Activity#isChangingConfigurations == true
, , .) , , - .
. 1, . / .
. , , , , , - .
, , : , . , , , .
, . , , 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
لا يزال بإمكانك استخدامه بأمان.