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
, Parcelable
dan yang lainnya Bundle
tidak 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.
Komplikasi kode.
- , , , . , , - . - : , , .
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
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.ViewModel
akan menyebabkan crash, tidak seperti onSaveInstanceState()
. Namun dalam kehidupan nyata, tampaknya, androidx.lifecycle.ViewModel
Anda masih bisa menggunakannya dengan aman.