SlideShare a Scribd company logo
State Management
in Android Applications
Gabor Varadi
@zhuinden
What is the problem, and why are we
solving it?
State management in android applications
State management in android applications
State management in android applications
State management in android applications
State management in android applications
Core App Quality Guidelines
From https://developer.android.com/docs/quality-guidelines/core-app-quality#fn
„When returning to the foreground, the app
must restore the preserved state and any
significant stateful transaction that was
pending, such as changes to editable fields,
game progress, menus, videos, and other
sections of the app.
How to induce process death?
• Step 1: put app in background with HOME
• Step 2: press „Terminate application”
• Step 3: restart app from launcher
For apps you don’t own
https://play.google.com/store/apps/details?id=me.empirical.android.application.fillme
mory&hl=en
Common mistakes
Expecting Singletons / statics to survive
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fab.setOnClickListener { view ->
ObjectHolder.myObject = MyObject("someName", 27)
startActivity(intentFor<SecondActivity>())
}
}
}
class SecondActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
inputName.text = ObjectHolder.myObject.name
}
}
05-08 14:05:39.845 3601-3601/com.zhuinden.processdeathexample D/AndroidRuntime:
Shutting down VM
05-08 14:05:39.845 3601-3601/com.zhuinden.processdeathexample E/AndroidRuntime: FATAL
EXCEPTION: main
Process: com.zhuinden.processdeathexample, PID: 3601
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.zhuinden.processdeathexample/com.zhuinden.processdeathexample.SecondA
ctivity}: kotlin.UninitializedPropertyAccessException: lateinit property myObject has
not been initialized
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property myObject has
not been initialized
at com.zhuinden.processdeathexample.ObjectHolder.getMyObject(ObjectHolder.kt:4)
at
com.zhuinden.processdeathexample.SecondActivity.onCreate(SecondActivity.kt:12)
Expecting Singletons / statics to survive
„savedInstanceState == null for
the first launch”?
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
// „don’t refetch data after rotation”
if (savedInstanceState == null) {
loadData();
}
// ...
}
„savedInstanceState == null for
the first launch”-- nope
„savedInstanceState == null for
the first launch”-- nope
„savedInstanceState == null for
the first launch” -- nope
HOWEVER:
• Fragments ARE recreated by super.onCreate()
• The first fragment MUST be added in a
if(savedInstanceState == null) check
FragmentPagerAdapter.getItem()?
private fun initFragment() {
homeFragment = HomeScreenFragment.newInstance()
incidentFragment = IncidentFragment.newInstance()
weatherFragment = WeatherFragment.newInstance()
val fm = supportFragmentManager
viewPager.adapter = object: FragmentPagerAdapter(fm) {
override fun getItem(position: Int): Fragment =
when (position) {
0 -> homeFragment
1 -> incidentFragment
2 -> weatherFragment
}
}
}
Should probably be „createFragment”
Process: XXXXXX, PID: 3192 kotlin.UninitializedPropertyAccessException:
lateinit property has not been initialized
at xxx.ui.IncidentScreenFragment.showData(IncidentScreenFragment.kt:78)
at xxx.ui.home.HomeActivity.filterData(HomeActivity.kt:110)
Should probably be „createFragment”
Fixed version:
viewPager.adapter = object: FragmentPagerAdapter(fm) {
override fun getItem(position: Int): Fragment =
when (position) {
0 -> HomeFragment.newInstance()
1 -> IncidentFragment.newInstance()
2 -> WeatherFragment.newInstance()
}
}
Don’t trust savedInstanceState after
Fragment.onCreate
• The savedInstanceState inside
onCreateView and after can be out of date
• onSaveInstanceState to Bundle is not called
when a Fragment is detach()/attach()ed
Will Jetpack help me?
State management in android applications
State management in android applications
Jetpack: Saving UI states
What needs to be persisted?
• Navigation state is already managed by the
system on Android out of the box*
– Empty ctor + using intent extras / fragment arguments
• Screen state is partially managed by the system
– Views with IDs have their state persisted
– Complex state (f.ex. RecyclerView selection) are not
persisted automatically
– Dynamically added views should be recreatable
Example for saving/restoring state
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
selectedSportId = savedInstanceState.getLong("selectedSportId")
selectedPosition = savedInstanceState.getInt("selectedPosition")
selectedTags.clear()
selectedTags.addAll(
savedInstanceState.getStringArrayList("selectedTags"))
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putLong("selectedSportId", selectedSportId)
outState.putInt("selectedPosition", selectedPosition)
outState.putStringArrayList("selectedTags", ArrayList(selectedTags))
}
What SHOULDN’T be persisted?
• Data
– Bundle has a size limit
– Data should be fetched asynchronously, off the UI
thread
• Transient state
– „Loading” state: computed from progress of side-
effect („something is happening”, but is it really?)
Single object state?
Single object state!
@Parcelize
data class PersonViewState(
// loading should come from elsewhere
val personFilter: String = "",
val unhandledError: ErrorType? = null // enum or sealed class
): Parcelable
...but is this really necessary?
Loading data
• Asynchronous loading should either begin on
initialization, or when observed
• Jetpack: store LiveData inside ViewModel, and expose
it to observers – fetch begins when observed
• Data can be loaded via a Transformation chain from a
MutableLiveData that stores the state – changes trigger
new data load
• Note: LiveData is analogous with BehaviorRelay
Saving state of a ViewModel
class MainViewModel: ViewModel() {
private val _selectedPosition = MutableLiveData<Int>()
fun saveState(bundle: Bundle) {
bundle.putInt("selectedPosition", _selectedPosition.value)
}
fun restoreState(bundle: Bundle) {
_selectedPosition.value = bundle.getInt("selectedPosition")
}
}
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(this, object: ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
MainViewModel().let { viewModel ->
savedInstanceState?.getBundle("viewModelState")?.let { bundle ->
viewModel.restoreState(bundle)
}
} as T
}).get(MainViewModel::class.java)
...
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val viewModelState = Bundle().also { bundle ->
viewModel.saveState(bundle)
}
outState.putBundle("viewModelState", viewModelState)
}
}
Jetpack: SavedState
private val mainViewModel by viewModels { ... }
class MainViewModel(
private val sportDao: SportDao
private val handle: SavedStateHandle
): ViewModel() {
private val _selectedSportId = handle.getLiveData("selectedSportId")
private val _selectedPosition = handle.getLiveData("selectedPosition")
val sport = _selectedSportId.switchMap { sportDao.getSport(it) }
val selectedPosition: LiveData<Int>
get() = _selectedPosition
}
Jetpack: SavedState
class MainViewModelFactory(
private val sportDao: SportDao,
owner: SavedStateRegistryOwner,
defaultState: Bundle?
): AbstractSavedStateVMFactory(owner, defaultState) {
override fun <T: ViewModel?> create(
key: String, modelClass: Class<T>, handle: SavedStateHandle
): T = MainViewModel(sportDao, handle) as T
}
DEMO?
Talks to watch
Fred Porciúncula: A Dagger Journey
https://www.youtube.com/watch?v=9fn5s8_CYJI
Fun with LiveData (Android Dev Summit '18)
https://www.youtube.com/watch?v=2rO4r-JOQtA
Google I/O Day 2: What’s new in Architecture
Components
https://www.youtube.com/watch?v=Qxj2eBmXLHg&list=PLOU2XLYxms
ILVTiOlMJdo7RQS55jYhsMi&index=29
Thank you for your attention!
Q/A?

More Related Content

PPTX
Paging Like A Pro
PPTX
Reactive state management with Jetpack Components
PDF
Simplified Android Development with Simple-Stack
PPTX
Architecting Single Activity Applications (With or Without Fragments)
PPTX
Guide to Destroying Codebases The Demise of Clever Code
PDF
Evan Schultz - Angular Camp - ng2-redux
PDF
Introduction to React & Redux
PDF
React + Redux. Best practices
Paging Like A Pro
Reactive state management with Jetpack Components
Simplified Android Development with Simple-Stack
Architecting Single Activity Applications (With or Without Fragments)
Guide to Destroying Codebases The Demise of Clever Code
Evan Schultz - Angular Camp - ng2-redux
Introduction to React & Redux
React + Redux. Best practices

What's hot (20)

PDF
Building React Applications with Redux
PDF
"Migrate large gwt applications - Lessons Learned" By Harald Pehl
PDF
Evan Schultz - Angular Summit - 2016
PDF
Practical Protocol-Oriented-Programming
PDF
Let's Redux!
PDF
React – Structure Container Component In Meteor
PDF
Workshop 20: ReactJS Part II Flux Pattern & Redux
PPTX
Getting started with ReactJS
PDF
Intro to ReactJS
PDF
Workshop 26: React Native - The Native Side
PDF
Introduction to ReactJS and Redux
PDF
State Models for React with Redux
PDF
Redux with angular 2 - workshop 2016
PDF
Paging using Paging 3
PDF
Android programming -_pushing_the_limits
PDF
React & Redux
PDF
Angular 2 Component Communication - Talk by Rob McDiarmid
PDF
Intro to Retrofit 2 and RxJava2
PDF
Let's discover React and Redux with TypeScript
PPTX
Better React state management with Redux
Building React Applications with Redux
"Migrate large gwt applications - Lessons Learned" By Harald Pehl
Evan Schultz - Angular Summit - 2016
Practical Protocol-Oriented-Programming
Let's Redux!
React – Structure Container Component In Meteor
Workshop 20: ReactJS Part II Flux Pattern & Redux
Getting started with ReactJS
Intro to ReactJS
Workshop 26: React Native - The Native Side
Introduction to ReactJS and Redux
State Models for React with Redux
Redux with angular 2 - workshop 2016
Paging using Paging 3
Android programming -_pushing_the_limits
React & Redux
Angular 2 Component Communication - Talk by Rob McDiarmid
Intro to Retrofit 2 and RxJava2
Let's discover React and Redux with TypeScript
Better React state management with Redux
Ad

Similar to State management in android applications (20)

PDF
Gabor Varadi - Reactive State Management with Jetpack Components
PDF
Android Jetpack: ViewModel and Testing
PDF
Don't Make Android Bad... Again
PDF
Building Testable Reactive Apps with MVI
PDF
MVI - Managing State The Kotlin Way
PDF
Android architecture components - how they fit in good old architectural patt...
PPTX
Common mistakes in android development
PDF
02 programmation mobile - android - (activity, view, fragment)
PDF
MVVM In real life - Lea Cohen Tannoudji, Lightricks
PDF
Survive the lifecycle
PDF
Working effectively with ViewModels and TDD - UA Mobile 2019
PDF
Deep dive into android restoration - DroidCon Paris 2014
PDF
Dialogs in Android MVVM (14.11.2019)
PDF
Android Jetpack + Coroutines: To infinity and beyond
PDF
Cleaning your architecture with android architecture components
PDF
Handling Lifecycles in a Jetpack way
PDF
Reuse features in Android applications
PDF
Android Best Practices - Thoughts from the Trenches
PDF
MVM - It's all in the (Implementation) Details
PPTX
MVM - It's all in the (Implementation) Details
Gabor Varadi - Reactive State Management with Jetpack Components
Android Jetpack: ViewModel and Testing
Don't Make Android Bad... Again
Building Testable Reactive Apps with MVI
MVI - Managing State The Kotlin Way
Android architecture components - how they fit in good old architectural patt...
Common mistakes in android development
02 programmation mobile - android - (activity, view, fragment)
MVVM In real life - Lea Cohen Tannoudji, Lightricks
Survive the lifecycle
Working effectively with ViewModels and TDD - UA Mobile 2019
Deep dive into android restoration - DroidCon Paris 2014
Dialogs in Android MVVM (14.11.2019)
Android Jetpack + Coroutines: To infinity and beyond
Cleaning your architecture with android architecture components
Handling Lifecycles in a Jetpack way
Reuse features in Android applications
Android Best Practices - Thoughts from the Trenches
MVM - It's all in the (Implementation) Details
MVM - It's all in the (Implementation) Details
Ad

Recently uploaded (20)

PDF
System and Network Administraation Chapter 3
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PPTX
Reimagine Home Health with the Power of Agentic AI​
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
medical staffing services at VALiNTRY
PPTX
Computer Software and OS of computer science of grade 11.pptx
PPT
Introduction Database Management System for Course Database
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PPTX
assetexplorer- product-overview - presentation
PPTX
L1 - Introduction to python Backend.pptx
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PPTX
ai tools demonstartion for schools and inter college
PDF
top salesforce developer skills in 2025.pdf
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
System and Network Administraation Chapter 3
Design an Analysis of Algorithms II-SECS-1021-03
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Navsoft: AI-Powered Business Solutions & Custom Software Development
Odoo Companies in India – Driving Business Transformation.pdf
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Reimagine Home Health with the Power of Agentic AI​
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
medical staffing services at VALiNTRY
Computer Software and OS of computer science of grade 11.pptx
Introduction Database Management System for Course Database
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
assetexplorer- product-overview - presentation
L1 - Introduction to python Backend.pptx
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
How to Migrate SBCGlobal Email to Yahoo Easily
ai tools demonstartion for schools and inter college
top salesforce developer skills in 2025.pdf
Wondershare Filmora 15 Crack With Activation Key [2025

State management in android applications

  • 1. State Management in Android Applications Gabor Varadi @zhuinden
  • 2. What is the problem, and why are we solving it?
  • 8. Core App Quality Guidelines From https://developer.android.com/docs/quality-guidelines/core-app-quality#fn „When returning to the foreground, the app must restore the preserved state and any significant stateful transaction that was pending, such as changes to editable fields, game progress, menus, videos, and other sections of the app.
  • 9. How to induce process death? • Step 1: put app in background with HOME • Step 2: press „Terminate application” • Step 3: restart app from launcher
  • 10. For apps you don’t own https://play.google.com/store/apps/details?id=me.empirical.android.application.fillme mory&hl=en
  • 12. Expecting Singletons / statics to survive class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) fab.setOnClickListener { view -> ObjectHolder.myObject = MyObject("someName", 27) startActivity(intentFor<SecondActivity>()) } } } class SecondActivity: AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_second) inputName.text = ObjectHolder.myObject.name } }
  • 13. 05-08 14:05:39.845 3601-3601/com.zhuinden.processdeathexample D/AndroidRuntime: Shutting down VM 05-08 14:05:39.845 3601-3601/com.zhuinden.processdeathexample E/AndroidRuntime: FATAL EXCEPTION: main Process: com.zhuinden.processdeathexample, PID: 3601 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.zhuinden.processdeathexample/com.zhuinden.processdeathexample.SecondA ctivity}: kotlin.UninitializedPropertyAccessException: lateinit property myObject has not been initialized at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) Caused by: kotlin.UninitializedPropertyAccessException: lateinit property myObject has not been initialized at com.zhuinden.processdeathexample.ObjectHolder.getMyObject(ObjectHolder.kt:4) at com.zhuinden.processdeathexample.SecondActivity.onCreate(SecondActivity.kt:12) Expecting Singletons / statics to survive
  • 14. „savedInstanceState == null for the first launch”? override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState); // „don’t refetch data after rotation” if (savedInstanceState == null) { loadData(); } // ... }
  • 15. „savedInstanceState == null for the first launch”-- nope
  • 16. „savedInstanceState == null for the first launch”-- nope
  • 17. „savedInstanceState == null for the first launch” -- nope HOWEVER: • Fragments ARE recreated by super.onCreate() • The first fragment MUST be added in a if(savedInstanceState == null) check
  • 18. FragmentPagerAdapter.getItem()? private fun initFragment() { homeFragment = HomeScreenFragment.newInstance() incidentFragment = IncidentFragment.newInstance() weatherFragment = WeatherFragment.newInstance() val fm = supportFragmentManager viewPager.adapter = object: FragmentPagerAdapter(fm) { override fun getItem(position: Int): Fragment = when (position) { 0 -> homeFragment 1 -> incidentFragment 2 -> weatherFragment } } }
  • 19. Should probably be „createFragment” Process: XXXXXX, PID: 3192 kotlin.UninitializedPropertyAccessException: lateinit property has not been initialized at xxx.ui.IncidentScreenFragment.showData(IncidentScreenFragment.kt:78) at xxx.ui.home.HomeActivity.filterData(HomeActivity.kt:110)
  • 20. Should probably be „createFragment” Fixed version: viewPager.adapter = object: FragmentPagerAdapter(fm) { override fun getItem(position: Int): Fragment = when (position) { 0 -> HomeFragment.newInstance() 1 -> IncidentFragment.newInstance() 2 -> WeatherFragment.newInstance() } }
  • 21. Don’t trust savedInstanceState after Fragment.onCreate • The savedInstanceState inside onCreateView and after can be out of date • onSaveInstanceState to Bundle is not called when a Fragment is detach()/attach()ed
  • 26. What needs to be persisted? • Navigation state is already managed by the system on Android out of the box* – Empty ctor + using intent extras / fragment arguments • Screen state is partially managed by the system – Views with IDs have their state persisted – Complex state (f.ex. RecyclerView selection) are not persisted automatically – Dynamically added views should be recreatable
  • 27. Example for saving/restoring state override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (savedInstanceState != null) { selectedSportId = savedInstanceState.getLong("selectedSportId") selectedPosition = savedInstanceState.getInt("selectedPosition") selectedTags.clear() selectedTags.addAll( savedInstanceState.getStringArrayList("selectedTags")) } } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putLong("selectedSportId", selectedSportId) outState.putInt("selectedPosition", selectedPosition) outState.putStringArrayList("selectedTags", ArrayList(selectedTags)) }
  • 28. What SHOULDN’T be persisted? • Data – Bundle has a size limit – Data should be fetched asynchronously, off the UI thread • Transient state – „Loading” state: computed from progress of side- effect („something is happening”, but is it really?)
  • 30. Single object state! @Parcelize data class PersonViewState( // loading should come from elsewhere val personFilter: String = "", val unhandledError: ErrorType? = null // enum or sealed class ): Parcelable ...but is this really necessary?
  • 31. Loading data • Asynchronous loading should either begin on initialization, or when observed • Jetpack: store LiveData inside ViewModel, and expose it to observers – fetch begins when observed • Data can be loaded via a Transformation chain from a MutableLiveData that stores the state – changes trigger new data load • Note: LiveData is analogous with BehaviorRelay
  • 32. Saving state of a ViewModel class MainViewModel: ViewModel() { private val _selectedPosition = MutableLiveData<Int>() fun saveState(bundle: Bundle) { bundle.putInt("selectedPosition", _selectedPosition.value) } fun restoreState(bundle: Bundle) { _selectedPosition.value = bundle.getInt("selectedPosition") } }
  • 33. class MainActivity : AppCompatActivity() { private lateinit var viewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProviders.of(this, object: ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T = MainViewModel().let { viewModel -> savedInstanceState?.getBundle("viewModelState")?.let { bundle -> viewModel.restoreState(bundle) } } as T }).get(MainViewModel::class.java) ... } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) val viewModelState = Bundle().also { bundle -> viewModel.saveState(bundle) } outState.putBundle("viewModelState", viewModelState) } }
  • 34. Jetpack: SavedState private val mainViewModel by viewModels { ... } class MainViewModel( private val sportDao: SportDao private val handle: SavedStateHandle ): ViewModel() { private val _selectedSportId = handle.getLiveData("selectedSportId") private val _selectedPosition = handle.getLiveData("selectedPosition") val sport = _selectedSportId.switchMap { sportDao.getSport(it) } val selectedPosition: LiveData<Int> get() = _selectedPosition }
  • 35. Jetpack: SavedState class MainViewModelFactory( private val sportDao: SportDao, owner: SavedStateRegistryOwner, defaultState: Bundle? ): AbstractSavedStateVMFactory(owner, defaultState) { override fun <T: ViewModel?> create( key: String, modelClass: Class<T>, handle: SavedStateHandle ): T = MainViewModel(sportDao, handle) as T }
  • 36. DEMO?
  • 37. Talks to watch Fred Porciúncula: A Dagger Journey https://www.youtube.com/watch?v=9fn5s8_CYJI Fun with LiveData (Android Dev Summit '18) https://www.youtube.com/watch?v=2rO4r-JOQtA Google I/O Day 2: What’s new in Architecture Components https://www.youtube.com/watch?v=Qxj2eBmXLHg&list=PLOU2XLYxms ILVTiOlMJdo7RQS55jYhsMi&index=29
  • 38. Thank you for your attention! Q/A?