Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Where Did My State Go? - WWC Mobile

Where Did My State Go? - WWC Mobile

Subhrajyoti Sen

December 22, 2020
Tweet

More Decks by Subhrajyoti Sen

Other Decks in Programming

Transcript

  1. NO

  2. NO

  3. Reasons 1. Dark Theme 2. Multi-Window 3. Process Death 4.

    Changing Language/ Font Scale 5. Permission Revocation
  4. Dark Theme Introduced in Android 10 Can be changed by

    1. System Toggle 2. AppCompat in-app
  5. Multi-Window Introduced in Android N A slight change in Lifecycle.

    You can’t completely depend on onPause() and onResume()
  6. Multi-Window Introduced in Android N A slight change in Lifecycle.

    You can’t completely depend on onPause() and onResume() screenOrientation will be ignored
  7. Process Death • The device is running low on memory

    and the OS kills your app to free up memory.
  8. Process Death • The device is running low on memory

    and the OS kills your app to free up memory. • It happens if your app is in the Paused/Stopped state.
  9. Process Death • The device is running low on memory

    and the OS kills your app to free up memory. • It happens if your app is in the Paused/Stopped state. • Cannot work around it.
  10. Process Death - Testing 1. Developer Options -> Apps ->

    Background process limit 2. Choose ‘No background processes’ 3. Open your app and put in the background 4. Open another app and switch to your app
  11. Process Death - Testing 1. Put the app in background

    2. adb shell am kill packagename
  12. ViewModel ViewModels persist state across Activity recreation. ViewModels do not

    persist state on process death. Use SavedStateHandle to save state.
  13. ViewModel - SavedStateHandle val viewModel = ViewModelProvider(this, SavedStateVMFactory(this)) .get(MyViewModel::class.java) class

    MyViewModel(val state : SavedStateHandle) : ViewModel() { fun saveProductId(productId: String) { state.set("productId", productId) } fun getProductId(): String { return state.get("productId")?: "" } }
  14. onSaveInstanceState is still valid class ProfileBottomSheet() : BottomSheetDialogFragment() { private

    lateinit var name: String override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) button.setOnClickListener { name = editText.text.toString()} } override fun onSaveInstanceState(outState: Bundle) { outState.putString("name", name) super.onSaveInstanceState(outState) } }
  15. Custom View Views can save their own state. Views need

    to have an ID to be able to save state.
  16. Custom View private class SavedState : BaseSavedState { var value

    = 1 constructor(superState: Parcelable) : super(superState) private constructor(source: Parcel) : super(source) { value = source.readInt() } override fun writeToParcel(out: Parcel, flags: Int) { super.writeToParcel(out, flags) out.writeInt(value) } }
  17. Custom View private class SavedState : BaseSavedState { //.. companion

    object { val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> { override fun createFromParcel(source: Parcel) = SavedState(source) override fun newArray(size: Int) = arrayOfNulls<SavedState?>(size) } } }
  18. Custom View class CustomView(context: Context) : View(context) { var value

    = 1 override fun onSaveInstanceState(): Parcelable { val superState = super.onSaveInstanceState() val state = SavedState(superState) state.value = this.value return state } }
  19. Custom View class CustomView(context: Context) : View(context) { override fun

    onRestoreInstanceState(state: Parcelable) { val savedState = state as SavedState super.onRestoreInstanceState(savedState.superState) this.value = savedState.value } }
  20. Fragment class ProfileBottomSheet(val name: String) : BottomSheetDialogFragment() { override fun

    onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) textview.setText(name) } }
  21. Testing Activity/Fragment Recreation Can be done with Espresso Easier with

    AndroidX Test debugImplementation 'androidx.fragment:fragment-testing:$fragment_version'
  22. Testing Fragment Recreation @RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testRecreation()

    { val scenario = launchFragmentInContainer<MyFragment>() // perform actions } }
  23. Testing Fragment Recreation @RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testRecreation()

    { val scenario = launchFragmentInContainer<MyFragment>() // perform actions scenario.recreate() } }
  24. Testing Fragment Recreation @RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testRecreation()

    { val scenario = launchFragmentInContainer<MyFragment>() // perform actions scenario.recreate() // test events } }
  25. Testing Fragment Lifecycle @RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testLifecycle()

    { val scenario = launchFragmentInContainer<MyFragment>() scenario.moveToState(State.CREATED) } }