I've read the Android Docs on the lifecycle of an activity. However, I am curious as to how different activities within an application behaves.
From some tests that I've done, transitioning from Activity A to Activity B within the same application via an intent pauses Activity A via onPause() and creates Activity B via onCreate().
The strange part is when Activity B transitions back to Activity A.
If the hardware back key is pressed, onPause() is fired for Activity B and onResume() is fired for Activity A. This is what I would expect.
However, if the back button on the ActionBar is pressed, onDestroy() is fired for Activity A followed by onCreate() and onResume().
Why is this so?
The "back button" on the ActionBar is called the "Up Button". This is the expected behaviour of the Up Button, if you take a look of the implementation of the code which performs the "up", you see that Activity A is recreated.
Intent parentActivityIntent = new Intent(getApplicationContext(), MainActivity.class);
parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(parentActivityIntent);
finish();
You can define what the "Up" button should do, however, I suggest to stick to the default behaviour.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// Your Code Here.
break;
}
}
Why?
The Up Button (in contrast to the back button) should navigate one level higher in the application hierarchy, always. The back button should go back, even if it will leave the current application.
You can't just call finish on the current Activity, because the parent Activity could already be garbage collected and don't exist anymore.
I heavily suggest to read the official Android Design Guidelines, especially the part about Up vs Back.
Related
I'm currently learning the Activity Lifecyle. I noticed the following:
I have two Activitys, A and B.
When I open Activity B from Activity A, A gets stopped and B gets created and started.
When I press the Back Button on my device, B gets destroyed and A get restarted.
But when I use the Back / Up Botton of the Actionbar instead, B gets destroyed, A gets destroyed and then onCreate() is called.
Why gets A destroyed instead of restarted, when using the Up Botton in the ActionBar?
I hope my question is clear, if not please comment.
When you press the BACK button, this calls onBackPressed() in the current Activity. The default behaviour of that method (if not overridden in the Activity) is to call finish() on the Activity. This finishes the Activity and resumes the Activity which is underneath it.
The UP button is calling startActivity() with an Intent that is built like this:
Intent intent = new Intent(this, TargetActivityForUpButton.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
This code will remove all activities in the stack back to, and including, TargetActivityForUpButton. It then creates a new instance of TargetActivityForUpButton and launches that Actvity (you will see onCreate(), onStart(), onResume() called on the Activity.
See also the section "Navigate up to parent activity" in https://developer.android.com/training/implementing-navigation/ancestral
The device's back button is actually taking you back (to the previous activity). The action bar back button works similarly to an "Up" button (within the hierarchy of your app). This is why the action bar's back button won't take you outside of the app, whereas the device's back button will carry on taking you back, even outside of the app. The action bar exists within your app so it follows the activity's lifecycle methods and starts from scratch each time you go back, whereas the device is restarting from where it stopped.
EDIT:
The Back button appears in the system navigation bar and is used to navigate, in reverse chronological order, through the history of screens the user has recently worked with. It is generally based on the temporal relationships between screens, rather than the app's hierarchy.
(Read more here)
I have Activity A (Main) and Activity B.
Fact: Activity A has: android:launchMode="singleInstance"
Usual scenario is:
User launches application > Activity A.
User clicks an item > Activity B
3.A. If user clicks on back/up buttons > Back to A (without calling finish() on B)
User clicks the SAME item as before > Forth to B.
At this point he can go back and forth without new instances. It's all in the stack and it doesn't recreate activities. (All right!)
3.B. If user clicks Home, then goes to task manager and brings the app to front > Activity B (all good, so far)
If user clicks UP button, it goes to TASK MANAGER, and I want it to go to Activity A (back button is expected to work this way, so let's focus on UP button).
Here's the implementation I have in Activity B for BACK and UP buttons.
#Override
public void onBackPressed() {
moveTaskToBack(true);
// I don't want to finish() the activity, so the user can reclick the same
// item without reloading the whole activity again (webview slow when parsing html).
return;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
moveTaskToBack(true);
// I don't want to finish() the activity... idem.
// I need to implement here the bring Activity A to front
break;
}
}
So, what I want is: to "Go Back" to Activity A keeping the same idea of using the stack to reload Activity B if needed, without using Intents (unless it calls activity to front, without adding items to the stack.)
Let me know if I explained myself clearly and if you need more info.
UPDATE:
I've found this at: http://developer.android.com/training/implementing-navigation/ancestral.html
This is how I adapted it.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent upIntent = new Intent(this, Activity_A.class);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities();
} else {
moveTaskToBack(true); // I want it this way. Don't worry.
}
break;
}
}
But the method NavUtils.shouldUpRecreateTask is ALWAYS returning false.
I did the http://developer.android.com/training/implementing-navigation/ancestral.html#SpecifyParent part, so that's not the issue.
My problem is that I want to recognize if Activity A exists in the stack, for when i.e. the app is launched from the task manager.
How can I achieve this?
Thanks.
moveTaskToBack moves the entire task to the background. it doesn't finish the activity.
in order to have full control of activities, you have some possible solutions:
create your own global manager for the activities, monitor each of them through all of their lifecycle and decide what to do on each event.
you could also finish each activity as soon as you go from it, and put "it" (just its name or something) in a stack and restore its state when you come back to it.
use fragments instead, and manage them all on a single activity. be warned of configurations changes though.
I have created an application that has multiple pages and navigation from one to another represents a crucial flow. I don't want the user to be able to press the back button and escape the activity without first warning him and then finally deleting all stack trace such that when the activity is launched again it starts afresh.
As of yet I have been using something similar to the function below :
#Override
public void onBackPressed()
{
this.finish();
Intent int1= new Intent(this, Home.class);
int1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(int1);
super.onBackPressed();
}
But sometimes when after quitting the application when I launch it again it restarts from some random page or the one from where I quit the application (basically not the home screen from where it is expected to start)
I cannot think of a cleaner way to quit the application other than clearing all the previous activity flags as described in the code.
Any help on the above is appreciated!
EDIT :
Anytime during the flow of my activity if the user presses the back button, I want the control to be thrown back to the main page (clearing all the previous activity stack traces). Such that in case someone re-lanches the application it will re start normally from the main page.
You don't need any of this custom code in onBackPressed(). All you need to do is add this to all of your <activity> definitions in the manifest (except the root activity):
android:noHistory="true"
This ensures that none of your activities (expect the root activity) is recorded in the back stack. When the user clicks the BACK key, it will just return to the root activity.
Another benefit of this is that if the user leaves your app (by clicking HOME or by pulling down the notification bar and clicking on a notification, when he returns to your app it will also just return to your root activity.
Anytime during the flow of my activity if the user presses the back
button, I want the control to be thrown back to the main page
(clearing all the previous activity stack traces).
This can be done just by finishing all the activities as they move forward, except the MainActivity.
Such that in case someone re-lanches the application it will re start
normally from the main page.
Is it like if user is in Activity_5 and uses Home Button and relaunches the app again, MainActicity must appear?
IF so, you can call finish() in onPause() of every Activity except MainActivity
EDIT:
Might not be the perfect solution, but this is what I did to achieve exactly the same(logout in my application):
OnBackPressed() in any activity updates a boolean shared preference say backPressed to true and in onResume() of all the Activities, except MainActivity check its value and finish if true.
#Override
protected void onResume() {
super.onResume();
SharedPreferences mSP = getSharedPreferences(
"your_preferences", 0);
if (mSP .getBoolean("backPressed", false)) {
finish();
}
}
Back Button is used to go back to the previous activity. So i would not override the back button to clear activity stack. I suggest you use a Action Bar for this purpose. Navigate to Home Screen of the application using the application icon.
http://developer.android.com/guide/topics/ui/actionbar.html
Also check this link and comments below the answer by warrenfaith
android - onBackPressed() not working for me
#Override
public void onBackPressed()
{
moveTaskToBack(true);
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
you can use that code, it's work for me!
I have two Activities, A and B. Here is a normal scenario: A is running, then sends an intent to B. A is paused, and B displays. When the user presses the back button from B, B us destroyed and the user is returned to A.
However, there is a case where B needs to re-create itself. To do this, I call finish() and then startActivity() on B and that works fine. But then, when I click the back button, it shows B again, and so I need to click the back button once more to get back to A.
How can I re-start B, but still be able to press the back button only once to return to A?
The following will dispose of the current activity while launching the next intent:
Intent launchNext = new Intent(getApplicationContext(), NextActivity.class);
launchNext.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(launchNext);
To override the back button, use the following:
#Override
public void onBackPressed() {
super.onBackPressed();
this.finish(); // or do something else
}
This can be solved by taking a closer look at your intent flags. Check out http://developer.android.com/reference/android/content/Intent.html and they give more information about what lifecycle you are shooting for.
Also, don't forget that you can override the back button functionality.
This may be helpful in case you want to manage your life cycle more closely.
For example, you can also make sure to go back to A if back from B. And close your app if back on A.
I want to implement Navigation Pattern in my app with Up button in ActionBar.
I have Details Activity, here I can come from home, favorites and search screen. Also I can open this screen from browser(handling specific url). When user press Up button, I use flush() method, to emulate back navigation. But for case, when user come from browser, I want to open home screen instead of previous browser activity. How I can recognize, that previous activity was from another app, and navigate to home screen?
Up Should always navigate to the hierarchical parent of the activity and Back should always navigate temporally.
In other words you should leave Back as it is.
As for Up, it should always go to the same place no matter where it came from. So if you normally come to the DetailsActivity from YourListActivity, Up should always go there no matter where you came from. What is the most likely place is up to your discretion, but it should always be the same.
If you come to the Details Activity from a non-normal location (such as the browser, another activity, widget, or notification) you should recreate your task stack so navigation using up results in the same path. Here is an example from the Android Developer Training:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent upIntent = new Intent(this, YourListActivity.class);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
// This activity is not part of the application's task, so
// create a new task
// with a synthesized back stack.
TaskStackBuilder
.from(this)
.addNextIntent(new Intent(this, HomeActivity.class))
.addNextIntent(upIntent).startActivities();
finish();
} else {
// This activity is part of the application's task, so simply
// navigate up to the hierarchical parent activity.
NavUtils.navigateUpTo(this, upIntent);
}
return true;
}
}
Here is the Android Training on Implementing Navigation
(http://developer.android.com/training/implementing-navigation/index.html).
You will need the support library for NavUtils and TaskStackBuilder.