Tracking the activity life cycle - android

I have requirement wherein I have to display a lock screen if the user moves out of the application.
Hence, the structure is: Activity A extends Activity B.
Wherein Activity B is the deciding activity : "was application in backgound".
If so it launches the lock activity.
Now, say I am on activity A and receive a phone call. Hence the app gets into the background.
When it resumes I can see the glimpse of Activity A for a fraction of second and then comes the lock activity.
Can there be any solution to avoid that glimpse of Activity A?

You can see the lifecycle of activity from official doc
You are using activity B just to track whether activity is alive. I am not sure if it is necesary.
If activity goes to background onPause() method is called, it means activity is not visible (it might be both screen lock or home button pressed), and onResume() is called when activity is visible again. In Activity A if you override onPause method and launch your lock activity, it should work. (Or set a boolean onPause and launch lock activity on resume(you might see Activiy A though)
Good luck

Related

Android Activity life cycle - onPause() and onResume()

In the Android developer diagram, I saw that onResume() is always called before onPause(). Assuming the user starts a new Activity, why should onPause() be preceded by onResume()?
I mean:
OnResume can be called in 2 occassions:
1) when user starting new activity (before OnPause)
2) when activity is in background and if the user brings the activity back to the
foreground
I expect in every case, something else should be done.
You are getting it wrong. Whenever an activity is created, onResume is called just after onStart. Whenever your activity goes back stack onPause is called. Again if your activity comes back to foreground then onResume is called. So, it is not like, onResume is called before onPause. Whenever activity is returning from onPause state, onResume gets called instead of onStart or onCreate. This happens so that Android does not have to create Activity instance again and again though those instances are not properly destroyed. This is quite memory efficient too.
NOTE: If you app is running and the user presses back button or home button, then the Activity goes through onPause() and onStop() state. After this if the user is again coming back to your app then, onRestart(), onStart() and onResume() will be called sequentially.
Then when the activity is only in onPause() state ? When a dialog surfaces on top of your activity or your activity is getting displayed in Split screen but it doesn't have focus (user is not interacting with your app). On these cases, activity goes to onPause() state only.
onResume() is always called before onPause()
This is correct. onResume is always called when the Activity is launched for the first time, before onCreate, and when the Activity is being resumed (user navigates back to your Activity)
Assuming the user starts a new Activity, why should onPause() be
preceded by onResume()
onPause is only called when the Activity is put to background, or before onDestroy if the Application is being destroyed. So onPause is always being called after a call to onResume has been made. Why? Because that's the lifecycle of the Activity as defined by the Android framework.
The life cycle of the activity is as follows
Fresh start via onCreate(), onStart(), onResume .... and close via onPause()->onStop()->onDestroy()
Yellow background: Activity goes into background and thus is no longer visible. The user returns back to the activity.
e.g.
Switch off the phone screen while the activity is running: onPause()->onStop()
Switch on the screen again: onStart() -> onResume()
Green background: The activity stays in the visible screen area but is not active
e.g. Activate multiple windows (split screen) occupying one part of the screen each and tip on your app to make it active
tip on the other app: onPause() is called in your app as it goes into pause but is still visible
tip on your app: onResume() is called
Here is an example of a split screen with two apps:
see android documentation on activity life cycle for details

How Onstop Method work for this demo?

I am making a demo to understand back stack and activity life-cycle.
I made:
MainActivity
MainActivityDialog (another activity theme as dialog)
BActivity
I launched this app and Main Activity is shown. Then press a button to show the dialog, then MainActivityDialog is opened. Then I again press button on MainActivityDialog then BActivity is opened. Finally, I pressed the back button.
MainActivity -> MainActivityDialog -> BActivity ---Back---> MainActivityDialog
Here is the log of this app :
My question are:
Why MainActivity get stopped after launching BActivity from MainActivityDialog? Then after BActivity lifecycle method is called, why MainActivityDialog get stopped?
After pressing back button in BActivity, MainActivity starts first then MainActivityDialog starts and then MainActivityDialog resume?
The order of calls to onStop() and onDestroy() on multiple activities is indeterminate.
If you have multiple activities in your activity stack that are no longer visible on screen, Android may call onStop() on them whenever it wants to and in whatever order it wants to. This is only an indication to the activity that it is no longer visible to the user. You cannot rely on the order of onStop() calls to multiple activities.
The same goes for onDestroy(). Android may call onDestroy() on an activity once that activity has finished. If you have multiple finished activities in your task, Android may call onDestroy() on them whenever it wants to and in whatever order it wants to. This is also indeterminate. The call to onDestroy() is just to inform the activity that it is no longer active and that it should release any resources it may have.
There is no guarantee that onStop() or onDestroy() will ever be called. The last lifecycle call that is guaranteed is onPause(). After that, Android can just kill the process without calling any further lifecycle methods.
In your second question you want to know why, after the user presses the BACK button on BActivity, MainActivity starts first followed by MainActivityDialog. The reason is that MainActivity is visible on screen FIRST and then MainActivityDialog is visible on screen on top of MainActivity (because MainActivityDialog is Dialog-themed, it doesn't cover the entire screen and you can see parts of MainActivity underneath it).
Im not a pro at Android, but since nobody has answered yet, i will try my best. I want to help because i also learn android by doing something like you did (using log cat to see activiti's current state) for the first time.
Why MainActivity get stopped after launching BActivity from
MainActivityDialog?
Every time you start a new activity, the old activity will always be paused/stopped.
Then after BActivity lifecycle method is called, why
MainActivityDialog get stopped?
Because now the current active activity is BActivity, in other word : MainActivityDialog is not active/visible hence its stopped/paused.
After pressing back button in BActivity, MainActivity starts first
then MainActivityDialog starts and then MainActivityDialog resume?
Yes, because you started MainActivityDialog from MainActivity, so MainActivity will be restarted first.
Please feel free to comment, im also still learning :)

Return to previous Activity without deleting current state - Android

I wrote an Android app with several Activities and a Main Activity. When I go from the Main Activity to lets say Activity B, I want to "pause" the Main Activity, when the back button is pressed it should go back and reactivate the Main Activity instead of calling onCreate().
This shall work with all Activities, so if I click on a button to start Activity B, it shall also reactivate the old Activity B instead of creating a new state with onCreate().
How can I realize this?
PS: I already tried it with parcelable, but this do only work, if I close the application or something unexpected happens.
It's always possible that the first activity may be destroyed when you start another activity. It will be recreated when you go back to it. Every app should be written with this possibility in mind. To make sure your activities can handle being destroyed and recreated, turn on the "don't keep activities" developer option.
It is by default in Android. If you Start Activity B from Activity A then activity A goes in stopped state. Below methods will be called of Activity A
onPause()
onStop()
When you tap on Back key on Activity B. Below methods of Activity A will be called.
onRestart()
onStart()
onResume()
For reactivating Activity B, you can set Activity B launch mode as singleInstance. This will make sure that only single instance of Activity B will be created. onCreate will be not be called again. onNewIntent will be called when that activity is reactivated.
Refer: http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
Activities live in stack order. Each activity has its life cycle. When you close an activity (Activity B in your example) it eventually reaches onDestroy() method and removed from the stack order. It is by default in Android and there's nothing you can do about it.
What you can do is rewrite the onStop() method in Activity B and save some activity data (like text in EditText, for example) in SharedPreferences - read here. Then in your onCreate() method you can call for SharedPreferences, check if it's not empty and restore the text in the EditText by pulling appropriate value by key.

Differentiate home button pressed, back button pressed and new activity launched

I have a FragmentActivity. Within its onPause function, I would like to differentiate
Home button pressed
Back button pressed
Launching a new activity (This will cause the fragment activity's onPause being called)
For back button pressed case, I know I can differentiate it by using this.isFinishing() == true.
However, how about launching a new activity case?
I know perhaps I can set a flag before launching the new activity, and reset the flag, at the end of onPause function. But, it doesn't sound elegant to me. Is there any better and robust way?
You can create a singleton class that tracks when your activities start/resume/pause/stop. Make a base Activity class that calls the singleton in each of its lifecycle callbacks.
If you look at the order of the callbacks when transitioning between activities, you should see this:
Pause Activity A
Create Activity B
Start Activity B
Resume Activity B
Stop Activity A
When your singleton gets called from Activity A's onStop(), you can check if there was a call from onResume() from another Activity (which clearly belongs to your app). If there wasn't, you know the user has changed apps or gone back to the home screen.
As for the back button press, you can check isFinishing(), or override Activity.onBackPressed() and do your bookkeeping there.

Is there any way to distinguish between an Android Activity onResume from the home screen?

Is there any way to tell whether an Activity is being resumed (i.e. onResume is called) from the home screen/launcher?
For example, if I have an Application with two activities, A and B.
Scenario 1:
Some user action on Activity A will invoke Activity B, bringing it into the foreground - moving Activity A into the background. As Activity A moves into the background, it goes through onPause() and onStop(). The user (now on Activity B) either finishes the Activity or hits the "back" button, bringing Activity A back to the foreground, causing an onRestart(), onStart(), onResume() sequence.
Scenario 2:
If the user hits the "home" button while Activity A is in the foreground and then re-invokes the Application from the launcher, it goes through the same lifecycle as in Scenario 1. I.e. User hits the "home" button. Activity goes through onPause() and onStop(). User launches the application again, causing Activity A go come back into the foreground, again going through the same onRestart(), onStart(), onResume() sequence as in Scenario 1.
As far as I can tell, the Activity has no way of knowing how it was resumed, it just knows it is being brought back into view. In fact, I have a feeling that there isn't really as much of a concept of an "Application" in Android - in the sense of something that has a single entry and exit point.
in Scenario 2, your activity will get an onNewIntent call, with the launcher intent passed to it.
You could capture the back button press on Activity B and pass an extra value to Activity A. If there is an extra value then the activity was resumed from pressing back on Activity B, if there is no extra value then the Activity was resumed from being hidden.
Could Acitivity A use startActivityForResult() to start Activity B and use onActivityResult() to detect that Activity B finished?
So the straightforward answer to the initial question is probably: no. Launching an activity from the home screen through an icon, or resuming it from the recents screen can not be observed from the intent it is (re)started/resumed with.
Depending on what you are trying to achieve there are some approaches though:
what #superfell suggested:
Check for whether the onNewIntent-method is called on your activity to decide if it was restarted from the launcher. As a precondition you need to set your activity to singleTask/singleTop launchMode in your Manifest:
android:launchMode="singleTask"
depending on what you're trying to achieve, this might be enough! But additionally you might have to deal with what happens when the user presses the back button. Default behavior is to finish & destroy your activity. Thus a brand new copy of it would be launched when it gets selected from the recents screen. Though onNewIntent would not be called, everything would be rebuilt from scratch. If you need to prevent this you can use:
override fun onBackPressed() {
moveTaskToBack(true)
}
finally when you navigate "back" from an activity you launched yourself onNewIntent will also not be called. If you further need to distinguish why your activity is resumed, you might want to start the 2nd activity with startActivityForResult so the onActivityResult is called when you get resumed.
Launcher activity & Intent extra
A completely different approach would be to have a "launcher" activity in your manifest that directly calls your "main" activity and finishes itself. When calling your main activity you can put an intent extra that allows your main activity to distinguish if it was just launched for the first time, or not. As the extra would be present on further onResumes, make sure to overwrite it the first time you "consume" it:
override fun onResume() {
super.onResume()
val firstLaunch = intent.getBooleanExtra(FIRST_LAUNCH, false)
intent.putExtra(FIRST_LAUNCH, false)
if (firstLaunch) {
// do something
}
}
and when starting from your "launcher" activity:
intent.putExtra(FIRST_LAUNCH, true)
startActivity(intent)

Categories

Resources