Share
The A, B and C of Lifecycle Components
[Droidcon Berlin '18] If you've been developing Android applications for a while now, you know the pain of handling the lifecycle just right. It’s a pain-point that has existed since the advent of Android, up until recently when Google released Architecture components. As an Android developer you are bugged by handling activity/fragment lifecycle and flow of data in tandem to the lifecycle changes day in and out. Making your code aware about the lifecycle of the process/activity/fragment makes you more confident as a developer and enables faster development. This session would enable you to understand Lifecycle components (ProcessLifecycleOwner, LifecycleOwner, LifecycleObserver) and how they are leveraged in other architecture components like LiveData and ViewModel.
Google Slides Link: https://docs.google.com/presentation/d/1b8mEH9hwwBxUiUk4xxib15sL7UIAYrP2TiSDXY9ZGS4
Nishant Srivastava
Transcript
116 slides
-
The Challenge Android activity lifecycle - Many states - Repeats
on configuration changes @nisrulz #DCBERLIN18 -
The Challenge Android activity lifecycle - Many states - Repeats
on configuration changes Not to forget... @nisrulz #DCBERLIN18 -
Lifecycle Components Series of classes designed to help deal with
lifecycles in a more consistent fashion. @nisrulz #DCBERLIN18 -
Lifecycle Components Series of classes designed to help deal with
lifecycles in a more consistent fashion. - Lifecycle - LifecycleOwner - LifecycleObserver @nisrulz #DCBERLIN18 -
Lifecycle Series of states an object can be in. For
Android: Object that defines Android lifecycle states. i.e. Activity & Fragment @nisrulz #DCBERLIN18 -
Lifecycle dependencies { def lifecycle_version = "1.1.1" // Support library
already depends on this (since v26.1.0) // Both AppCompatActivity & Support Fragment implement // LifecycleOwner interface. // Lifecycles only implementation "android.arch.lifecycle:runtime:$lifecycle_version" ... } @nisrulz #DCBERLIN18 -
Lifecycle // Source code public abstract class Lifecycle { //
Adds a LifecycleObserver addObserver(@NonNull LifecycleObserver observer) // Removes the given observer from the observers list removeObserver(@NonNull LifecycleObserver observer) // Current state of the Lifecycle getCurrentState() // Compares the lifecycle states isAtLeast(@NonNull State state) ... } @nisrulz #DCBERLIN18 -
Lifecycle // Source code public abstract class Lifecycle { //
Adds a LifecycleObserver addObserver(@NonNull LifecycleObserver observer) // Removes the given observer from the observers list removeObserver(@NonNull LifecycleObserver observer) // Current state of the Lifecycle getCurrentState() // Compares the lifecycle states isAtLeast(@NonNull State state) ... } @nisrulz #DCBERLIN18 -
Lifecycle // Source code public abstract class Lifecycle { //
Adds a LifecycleObserver addObserver(@NonNull LifecycleObserver observer) // Removes the given observer from the observers list removeObserver(@NonNull LifecycleObserver observer) // Current state of the Lifecycle getCurrentState() // Compares the lifecycle states isAtLeast(@NonNull State state) ... } @nisrulz #DCBERLIN18 -
LifecycleOwner Interface that goes through Android Lifecycle. // Source code
public interface LifecycleOwner { // Returns the Lifecycle of the provider. @NonNull Lifecycle getLifecycle(); } @nisrulz #DCBERLIN18 -
LifecycleOwner class MainActivity : AppCompatActivity() { // Missing myLifecycleObserver override
fun onResume() { // Add lifecycle observer lifecycle.addObserver(myLifecycleObserver) } override fun onStop() { // Remove lifecycle observer lifecycle.removeObserver(myLifecycleObserver) } } @nisrulz #DCBERLIN18 -
LifecycleOwner Fun Fact: Activities & fragments are not the only
things with lifecycle by default @nisrulz #DCBERLIN18 -
LifecycleOwner Fun Fact: Activities & fragments are not the only
things with lifecycle by default You also have - LifecycleService - ProcessLifecycleOwner @nisrulz #DCBERLIN18 -
LifecycleService A service that is also a LifecycleOwner // Source
code public class LifecycleService extends Service implements LifecycleOwner { ... } @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner - Class that tracks the lifecycle of - whole
application process or - all the activities combined @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner - Class that tracks the lifecycle of - whole
application process or - all the activities combined - Useful for reacting to app coming to foreground or going to background @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner dependencies { def lifecycle_version = "1.1.1" // For ProcessLifecycleOwner
implementation "android.arch.lifecycle:extensions:$lifecycle_version" ... } @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner ON_CREATE (Only 1 time) ON_START & ON_RESUME ON_PAUSE &
ON_STOP ON_DESTROY @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner ON_CREATE (Only 1 time) ON_START & ON_RESUME (First Activity
pass) ON_PAUSE & ON_STOP ON_DESTROY @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner ON_CREATE (Only 1 time) ON_START & ON_RESUME (First Activity
pass) ON_PAUSE & ON_STOP (after 700ms delay) ON_DESTROY @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner ON_CREATE (Only 1 time) ON_START & ON_RESUME (First Activity
pass) ON_PAUSE & ON_STOP (after 700ms delay) ON_DESTROY @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner ON_CREATE (Only 1 time) ON_START & ON_RESUME (First Activity
pass) ON_PAUSE & ON_STOP (after 700ms delay) ON_DESTROY @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner ON_PAUSE & ON_STOP (after 700ms delay) // Source code
public class ProcessLifecycleOwner implements LifecycleOwner { static final long TIMEOUT_MS = 700; //mls ... } @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner Guarantee that ProcessLifecycleOwner won’t send any events if activities
are - Destroyed - Recreated due to configuration change @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner Comes with cost: extension artifact automatically adds <provider> element
to your manifest @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner // Source code // Internal class to initialize Lifecycles.
public class ProcessLifecycleOwnerInitializer extends ContentProvider { @Override public boolean onCreate() { ... ProcessLifecycleOwner.init(getContext()); return true; } ... } @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner Side-effect: Inits ProcessLifecycleOwner even if your app does not
use it! @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner Side-effect: Inits ProcessLifecycleOwner even if your app does not
use it! Why? @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner Side-effect: Inits ProcessLifecycleOwner even if your app does not
use it! Why? So that ProcessLifecycleOwner can be invoked as soon as process starts @nisrulz #DCBERLIN18 -
Application.ActivityLifecycleCallback // Source code public interface ActivityLifecycleCallbacks { void onActivityCreated(Activity
var1, Bundle var2); ... void onActivitySaveInstanceState(Activity var1, Bundle var2); void onActivityDestroyed(Activity var1); } @nisrulz #DCBERLIN18 -
Application.ActivityLifecycleCallback // Register for the callback application .registerActivityLifecycleCallbacks(object: Application.ActivityLifecycleCallbacks{ override
fun onActivityCreated(activity: Activity?, bundle: Bundle?) {} ... }) @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner // Source code public class ProcessLifecycleOwner implements LifecycleOwner {
... void attach(Context context) { ... Application app = (Application) context.getApplicationContext(); app.registerActivityLifecycleCallbacks (new EmptyActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { .. } ... }); } } @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner // Source code public class ProcessLifecycleOwner implements LifecycleOwner {
... void attach(Context context) { ... Application app = (Application) context.getApplicationContext(); app.registerActivityLifecycleCallbacks (new EmptyActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { .. } ... }); } } @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner // Source code public class ProcessLifecycleOwner implements LifecycleOwner {
... void attach(Context context) { ... Application app = (Application) context.getApplicationContext(); app.registerActivityLifecycleCallbacks (new EmptyActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { .. } ... }); } } @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner // Source code class EmptyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks { @Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) { //Empty method body } ... } @nisrulz #DCBERLIN18 -
ProcessLifecycleOwner // Source code class EmptyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks { @Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) { //Empty method body } ... } @nisrulz #DCBERLIN18 -
LifecycleRegistry Implementation of Lifecycle that can handle multiple observers //
Source code public class LifecycleRegistry extends Lifecycle { ... } @nisrulz #DCBERLIN18 -
LifecycleRegistry Implementation of Lifecycle that can handle multiple observers //
Source code public class LifecycleRegistry extends Lifecycle { ... } However, you need to dispatch the events yourself. @nisrulz #DCBERLIN18 -
LifecycleRegistry class MyLifecycleOwner : LifecycleOwner { private var registry: LifecycleRegistry
= LifecycleRegistry(this) init { registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) } override fun getLifecycle(): Lifecycle = registry fun startListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_START) } fun stopListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) } } @nisrulz #DCBERLIN18 -
LifecycleRegistry class MyLifecycleOwner : LifecycleOwner { private var registry: LifecycleRegistry
= LifecycleRegistry(this) init { registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) } override fun getLifecycle(): Lifecycle = registry fun startListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_START) } fun stopListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) } } @nisrulz #DCBERLIN18 -
LifecycleRegistry class MyLifecycleOwner : LifecycleOwner { private var registry: LifecycleRegistry
= LifecycleRegistry(this) init { registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) } override fun getLifecycle(): Lifecycle = registry fun startListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_START) } fun stopListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) } } @nisrulz #DCBERLIN18 -
LifecycleRegistry class MyLifecycleOwner : LifecycleOwner { private var registry: LifecycleRegistry
= LifecycleRegistry(this) init { registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) } override fun getLifecycle(): Lifecycle = registry fun startListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_START) } fun stopListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) } } @nisrulz #DCBERLIN18 -
LifecycleRegistry class MyLifecycleOwner : LifecycleOwner { private var registry: LifecycleRegistry
= LifecycleRegistry(this) init { registry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) } override fun getLifecycle(): Lifecycle = registry fun startListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_START) } fun stopListening() { registry.handleLifecycleEvent(Lifecycle.Event.ON_STOP) } } @nisrulz #DCBERLIN18 -
LifecycleRegistry val myLifecycleOwner = MyLifecycleOwner() // Missing myLifecycleObserver // Add
lifecycle observer myLifecycleOwner.lifecycle.addObserver(myLifecycleObserver) // Remove lifecycle observer myLifecycleOwner.lifecycle.removeObserver(myLifecycleObserver) @nisrulz #DCBERLIN18 -
LifecycleObserver An interface for observing a Lifecycle // Source code
public interface LifecycleObserver { // Empty } @nisrulz #DCBERLIN18 -
LifecycleObserver Two ways to implement - Annotation - Callback Interface
@nisrulz #DCBERLIN18 -
LifecycleObserver dependencies { def lifecycle_version = "1.1.1" // For Annotation
Support annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" ... } @nisrulz #DCBERLIN18 -
LifecycleObserver class MyLifecycleObserver : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun init() {}
@OnLifecycleEvent(Lifecycle.Event.ON_START) fun onStart() {} ... @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun cleanup() {} } @nisrulz #DCBERLIN18 -
LifecycleObserver val myLifecycleOwner = MyLifecycleOwner() // Add lifecycle observer myLifecycleOwner.lifecycle.addObserver(myLifecycleObserver)
// Remove lifecycle observer myLifecycleOwner.lifecycle.removeObserver(myLifecycleObserver) @nisrulz #DCBERLIN18 -
LifecycleObserver val myLifecycleOwner = MyLifecycleOwner() val myLifecycleObserver = MyLifecycleObserver() //
Add lifecycle observer myLifecycleOwner.lifecycle.addObserver(myLifecycleObserver) // Remove lifecycle observer myLifecycleOwner.lifecycle.removeObserver(myLifecycleObserver) @nisrulz #DCBERLIN18 -
LifecycleObserver val myLifecycleOwner = MyLifecycleOwner() val myLifecycleObserver = MyLifecycleObserver() //
Add lifecycle observer myLifecycleOwner.lifecycle.addObserver(myLifecycleObserver) // Remove lifecycle observer myLifecycleOwner.lifecycle.removeObserver(myLifecycleObserver) @nisrulz #DCBERLIN18 -
DefaultLifecycleObserver Callback interface for listening to LifecycleOwner state changes. Recommended
over annotations if using Java 8 language. @nisrulz #DCBERLIN18 -
DefaultLifecycleObserver android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }
} dependencies { def lifecycle_version = "1.1.1" // For DefaultLifecycleObserver implementation "android.arch.lifecycle:common-java8:$lifecycle_version" ... } @nisrulz #DCBERLIN18 -
DefaultLifecycleObserver // Source code public interface DefaultLifecycleObserver extends FullLifecycleObserver {
@Override default void onCreate(@NonNull LifecycleOwner owner) { ... } ... @Override default void onDestroy(@NonNull LifecycleOwner owner) { ... } } @nisrulz #DCBERLIN18 -
DefaultLifecycleObserver // Source code interface FullLifecycleObserver extends LifecycleObserver { void
onCreate(LifecycleOwner owner); void onStart(LifecycleOwner owner); ... void onDestroy(LifecycleOwner owner); } @nisrulz #DCBERLIN18 -
DefaultLifecycleObserver class MyLifecycleObserver : DefaultLifecycleObserver { override fun onCreate(owner: LifecycleOwner)
{} ... override fun onDestroy(owner: LifecycleOwner) {} } @nisrulz #DCBERLIN18 -
LiveData A lifecycle aware base class for encapsulating loading data
@nisrulz #DCBERLIN18 -
LiveData A lifecycle aware base class for encapsulating loading data
Lightweight implementation of Observer pattern @nisrulz #DCBERLIN18 -
LiveData dependencies { def lifecycle_version = "1.1.1" // For LiveData
implementation "android.arch.lifecycle:livedata:$lifecycle_version" ... } @nisrulz #DCBERLIN18 -
LiveData // Source Code public abstract class LiveData<T> { ...
protected void postValue(T value) {...} ... @MainThread protected void setValue(T value) {...} ... protected void onActive() {...} protected void onInactive() {...} } @nisrulz #DCBERLIN18 -
LiveData // Source Code public abstract class LiveData<T> { ...
protected void postValue(T value) {...} // Sets the value async ... @MainThread protected void setValue(T value) {...} ... protected void onActive() {...} protected void onInactive() {...} } @nisrulz #DCBERLIN18 -
LiveData // Source Code public abstract class LiveData<T> { ...
protected void postValue(T value) {...} // Sets the value async ... @MainThread protected void setValue(T value) {...} // Sets the value sync ... protected void onActive() {...} protected void onInactive() {...} } @nisrulz #DCBERLIN18 -
LiveData // Source Code public abstract class LiveData<T> { ...
protected void postValue(T value) {...} // Sets the value async ... @MainThread protected void setValue(T value) {...} // Sets the value sync ... protected void onActive() {...} // Has active observers i.e in Start/Resume state protected void onInactive() {...} } @nisrulz #DCBERLIN18 -
LiveData // Source Code public abstract class LiveData<T> { ...
protected void postValue(T value) {...} // Sets the value async ... @MainThread protected void setValue(T value) {...} // Sets the value sync ... protected void onActive() {...} // Has active observers i.e in Start/Resume state protected void onInactive() {...} // Has 0 active observers } @nisrulz #DCBERLIN18 -
LiveData class MySensorLiveData(context: Context?) : LiveData<Float>() { val sensorManager: SensorManager?
= context? .getSystemService(Service.SENSOR_SERVICE) as SensorManager val sensorListener: SensorEventListener = object : SensorEventListener { override fun onSensorChanged(event: SensorEvent?) { // Set Value setValue(event?.values?.get(0)) } ... } } @nisrulz #DCBERLIN18 -
LiveData class MySensorLiveData(context: Context?) : LiveData<Float>() { val sensorManager: SensorManager?
= context? .getSystemService(Service.SENSOR_SERVICE) as SensorManager val sensorListener: SensorEventListener = object : SensorEventListener { override fun onSensorChanged(event: SensorEvent?) { // Set Value setValue(event?.values?.get(0)) } ... } } @nisrulz #DCBERLIN18 -
LiveData class MySensorLiveData(context: Context?) : LiveData<Float>() { ... override fun
onActive() { ... sensorManager?.registerListener(sensorListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_FASTEST) } override fun onInactive() { ... sensorManager.unregisterListener(sensorListener) } } @nisrulz #DCBERLIN18 -
LiveData class MySensorLiveData(context: Context?) : LiveData<Float>() { ... override fun
onActive() { ... sensorManager?.registerListener(sensorListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_FASTEST) } override fun onInactive() { ... sensorManager.unregisterListener(sensorListener) } } @nisrulz #DCBERLIN18 -
LiveData val mySensorLiveData = MySensorLiveData(this) // Observe for values mySensorLiveData.observe(this,
Observer<Float>{ floatVal -> // Update the UI }) @nisrulz #DCBERLIN18 -
ViewModel - Hold & manage UI related data in Lifecycle
conscious way - Survives configuration changes - Prevents unnecessary reloading of data @nisrulz #DCBERLIN18 -
ViewModel dependencies { def lifecycle_version = "1.1.1" // For ViewModel
implementation "android.arch.lifecycle:viewmodel:$lifecycle_version" ... } @nisrulz #DCBERLIN18 -
ViewModel // Source code public abstract class ViewModel { //
Called when ViewModel is destroyed protected void onCleared() { } } @nisrulz #DCBERLIN18 -
ViewModel class MyViewModel : ViewModel() { private val username =
MutableLiveData<String>() fun initExpensiveOperation() { // expensive operation, e.g. network request username.value = "Nishant" // username.setValue(“Nishant”) } fun getUsername(): LiveData<String> { return username } } @nisrulz #DCBERLIN18 -
ViewModel class MyViewModel : ViewModel() { private val username =
MutableLiveData<String>() fun initExpensiveOperation() { // expensive operation, e.g. network request username.value = "Nishant" // username.setValue(“Nishant”) } fun getUsername(): LiveData<String> { return username } } @nisrulz #DCBERLIN18 -
ViewModel class MyViewModel : ViewModel() { private val username =
MutableLiveData<String>() fun initExpensiveOperation() { // expensive operation, e.g. network request username.value = "Nishant" // username.setValue(“Nishant”) } fun getUsername(): LiveData<String> { return username } } @nisrulz #DCBERLIN18 -
ViewModel class MyViewModel : ViewModel() { private val username =
MutableLiveData<String>() fun initExpensiveOperation() { // expensive operation, e.g. network request username.value = "Nishant" // username.setValue(“Nishant”) } fun getUsername(): LiveData<String> { return username } } @nisrulz #DCBERLIN18 -
ViewModel class MyViewModel : ViewModel() { private val username =
MutableLiveData<String>() fun initExpensiveOperation() { // expensive operation, e.g. network request username.value = "Nishant" // username.setValue(“Nishant”) } fun getUsername(): LiveData<String> { return username } } @nisrulz #DCBERLIN18 -
ViewModel class MyViewModel : ViewModel() { private val username =
MutableLiveData<String>() fun initExpensiveOperation() { // expensive operation, e.g. network request username.value = "Nishant" // username.setValue(“Nishant”) } fun getUsername(): LiveData<String> { return username } } @nisrulz #DCBERLIN18 -
ViewModel val viewModel = ViewModelProviders .of(this) .get(MyViewModel::class.java) viewModel.getUsername().observe(this, Observer<String> {
text -> //Update the UI }) @nisrulz #DCBERLIN18 -
ViewModel val viewModel = ViewModelProviders .of(this) .get(MyViewModel::class.java) viewModel.getUsername().observe(this, Observer<String> {
text -> //Update the UI }) @nisrulz #DCBERLIN18 -
More Info Is your Android Library, Lifecycle-Aware? https://android.jlelse.eu/is-your-android-library-lifecycle-aware-127629d32dcc Official documentation
about lifecycle components d.android.com/topic/libraries/architecture/lifecycle Using ProcessLifecycleOwner for libraries example https://github.com/nisrulz/android-examples/tree/develop/UsingProcessLifecycleOwnerForLibs Using Lifecycle Components for libraries example https://github.com/nisrulz/android-examples/tree/develop/LifeCycleCompForLib @nisrulz #DCBERLIN18