Tuesday 11 August 2015

Activity Life Cycle - Twist


To understand this blog basic necessity is knowledge of Activity Life Cycle. Does not it sound weird!!! We are here to learn lifecycle and basic necessity is lifecycle itself. Yes it is, but you will understand in no time :) 

Lets put it this way, this blog puts light on Activity lifecycle in abnormal circumstances. Wait Wait!!! What exactly we mean by this. Don't worry you will understand soon.

Everyone who is working in Android knows this basic diagram , make sure you understand it before you move further :



This is Activity lifecycle in happy environment; when things are in your favour and your requirement is served with normal flags.

But software is not that easy, we get strange requirements all the time. In this post we will be specifically talking about these abnormal situations :

a) Android is running low on memory and it kills your activity
b) You are using FLAG CLEAR TOP while starting Activity OR singleTop in Manifest
c) You are dealing with point b and point a occurs (booooom!!!)

Most of you must be familiar with case a where Android is running low on memory and to make sure device performs well it keeps on clearing memory as soon as possible. So how does it impacts us as developer ?
Documentation of this particular case is pretty clear on the web. So not wasting much time of yours, Android provides you two more lifecycle methods in such scenarios.

i) onSaveInstanceState
ii) onRestoreInstanceState

As name suggests, these methods are simply plugged into your normal lifecycle and system gives you chance to preserve user state for best UX. It is like saying, "Hey dude, I need your space for time being; Could you please pick your belongings for now and when I return you, you can re arrange your items as they were before"

This task is done in onSaveInstanceState method which is called after onPause when Activity is going to destroy which is followed by expected onStop method. We have to fill data (which we want to preserve) in Bundle which is passed to us in parameters. 

Assuming Android is running out of memory and gonna kill your activity, So after onStop method System may Or may not call onDestroy method (However I have seen this method is being called all the time) and woossssss our activity is gone.

Now when user navigates back to our Activity, he expects to see the same state where he left. Nobody like filling those big forms Or even a small email id field if they have already done for you. In this case when system recreates our Activity it simply goes through normal lifecycle which is shown above in diagram with two modifications :

i) It passes the bundle back to us in onCreate method; this is the bundle which we filled in onSaveInstanceState. So we have our data back.
ii) It calls another method named "onRestoreInstanceState" after inStart is called. It too contains same bundle for us to preserve state back for user.


onCreate
onStart
onRestoreInstanceState
OnResume



And at the end of day, we have happy user :)



 - FLAG CLEAR TOP while starting Activity OR singleTop in Manifest -

There are two possibilities, Activity does not exist in task OR it does. If it does not exist, this is similar to starting a new activity with standard flag. Same lifecycle will be called as shown in above diagram.

If Activity instance is already there in task stack (Suppose it was started with Intent i1), in this case Android will simple call method "onNewIntent" followed by "onRestart" and then "onStart" -> "onResume". And from now onwards, getIntent will return you the new Intent which was received recently to start your activity. It sounds simple and believe me it is.


onNewIntent  (with New Intent say i2)
onReStart (i2)
onStart  (i2)
onResume  (i2)


- FLAG CLEAR TOP while starting Activity OR singleTop in Manifest  and Android goes low on memory-


This is the case which was driving me crazy and led me to write this post. Have patience and read, suppose you started an activity A with intent I1 and you navigate to other activity. Assume case a occurs and system is low on  memory and it destroys your activity with normal lifecycle as explained above.

Now if you start another intent (i2) for A1 with either FLAG CLEAR TOP or A1 is singletop; Now as we know our A1 logically exists in backstack but it has been destroyed. So to handle this case, system changes lifecycle a bit:

onCreate (with Intent i1)  - weird
onStart (with Intent i1)  - weird
onRestoreInstanceState   (with Intent i1) - weird
onNewIntent (with Intent i2) and from here onwards, we can show new data as per intent
onResume (with i2)


But the story does not end here, even it goes more complex sometimes. Now we have Activity A1 with Intent i2. Suppose user presses home button and activity goes in background with normal lifecycle.
Assume System is low on memory now, so Android destroys your activity with proper callbacks in onSaveInstanceState (Remember we are dealing with i2).

Now when user navigates back to activity and system re creates activity, it starts Activity with normal lifecycle methods

onCreate  (intent i1)
onStart (intent i1)
onRestoreInstanceState (intent i1)
OnResume (intent i1)

But the strange part here is it calls every thing with Intent i1 (This is intent with which Activity was originally created) But user is expecting to open it with Intent i2 data. 

So in this case, you can utilise onSaveInstance and onRestoreInstanceState to properly fill your data and take actions accordingly.

[NOTE : All this was tested by turning on "Don't keep Activities on" flag in developer options, feel free to correct anything which you believe is misleading]

"happy coding"

No comments:

Post a Comment