I have Activities A, B, and C in my app and they flow in that order. If I implement the Up button in C, I want it to go back to B. The code stub that Eclipse generated is this:
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
However, B expects extras to be passed from A in its onCreate method. The relationship between B and C is that C allows the user to set some settings that affect how B is displayed. I'm currently handling saving the changes in C in onPause(). Should I just finish() C when user presses Up instead of calling navigateUpFromSameTask(this)?
If you're going to be returning from C back to B your activity will be created again, if you use standard launch mode. onSaveInstanceState will not (reliably) work.
Declare the launch mode of your activity B as:
android:launchMode="singleTop"
in your AndroidManifest.xml, if you want to return to your activity. See docu and an explanation here.
I believe you're having a similar problem to this? Essentially, if you're going to be returning from C back to B, there's a possibility it's going to need to call onCreate() again. This means that the extras you obtain from the intent are going to be gone, so you have to store them with something like onSaveInstanceState.
Related
I have an Activity A which I launch with some extras(i.e. put some data to the Intent that starts the Activity). From this Activity I launch another Activity B. The problem is that when I get back from B to A, by calling finish(), A Activity's getIntent() method returns an Intent that contains no extras.
So, my questions is: Is this normal behavior? And is there some way that I can signal Activity A that I want it to keep the Intent it was started with.
Oh, and please note that I've overridden the onSaveInstanceState() in Activity A.
EDIT:
I'm no longer experiencing this behavior on my device. And I haven't changed anything in the code. I'm using a 3 year old device for testing. I wonder if this might have been caused by a glitch on the device?
I got it figured out. This issue only happens when I click on ActionBar's back arrow and not when I press the device's Back button. Because when Back button is pressed B Activity's finish() method is called and the app normally returns to the already created instance of Activity A, when ActionBar's back arrow is clicked by default the Activity B doesn't call the finish() method, instead it creates a new instance of the Activity A due to the Android lateral navigation functionality. So the solution was to Override the ActionBar's back arrow click functionality like this(method added to Activity B):
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
int itemId = menuItem.getItemId();
if (itemId == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(menuItem);
}
Is this normal behavior?
yes it is. Start B with startActivityForResult , and in A, override onActivityResult. Before finishing B call setResult(int, intent), filling up the intent with the data you want to return to A. onActivityResult get the same intent, as third parameter.
Yes The Behavior is Normal. If You want to start an Activity X from an Activity Y and get some data from X and return to Y then you have to use startActivityForResult(intent,request_code)
Then you need to override theonActivityResult()` method
In the Activity X after creating the intent and putting the data in the intent you need to do the following
setResult(RESUKT_OK,i);
`
I have three activities: A, B, C
From both Activities A,B I can call
startActivity(new Intent(this, C.class));
So the logic would be something like A->B->C or A->C .. now when I am in C, I would like to get back to B or A depending on from which activity was C started.
Now the question is, when I am in Activity C, how to get "Back" to the parent activity, from which I opened this activity C?
I have been trying something with NavUtils and Intent.FLAGS, but I was not successful.
BTW: I can not use finish() or onBackPressed(). I am using custom dynamic created theme in my app and when I use onBackPressed() it will show a default application theme (default white screen with icon) before the desired activity is loaded.
Thanks for any help.
in your manifest add this to activity C so this part solves the back button.
<activity
android:name="your.package.name.C"
android:launchMode="singleInstance" >
</activity>
lets solve up button:
you must use putExtra that indicates the parent of C activity. for example when you want to call it from activity B do this:
Intent i = new Intent(B.this,C.class);
i.putExtra(MY_PARENT,"B");
startActivity(i);
and in activity C store MY_PARENT value in a string called parent. then when the user press UP button read that and go to the parent.
that means in activity C :
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
Intent i = new Intent(C.this,Class.forName(parent));
startActivity(i);
return true;
}
return super.onOptionsItemSelected(item);
}
You may create and process too many objects in onCreate method of your Activity, so that causes the delay that you see before the desired activity get loaded...
You can do all those creation and processing in an AsyncTask and keep your onCreate method clean, then you won't see that delay anymore.
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.
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.
Let's consider simple DB access application with two activities:
A - list of entries from DB
B - input form to enter new data to DB, with two buttons: Save / Cancel
Application starts with A (list) and from A user may go to B (input form).
To make entering new data more efficient I created a widget to jump directly to B (PendingIntent).
The observed behaviour of the application is like that:
If the first action of the user is widget (empty back stack) => the application opens B and when user click Save or Cancel activity is finished and focus goes back to Android desktop.
If main application was started before (A is on back stack) => B is still properly opened from widget however when user click Save or Cancel focus goes back to A
The behaviour described in 2 is OK when user starts B from A. However I would like to avoid it when B is started from widget.
Any hints ?
I have a situation where I need to do something similar. My quick fix was to add a "EXTRA_LAUNCHED_BY_WIDGET" Extra to the Intent launched by the widget. Then, in my Activity I treat that as a special case.
I needed to override the Back button behaviour, but you could just as easily use this case elsewhere, e.g. in other overridden Activity methods.
#Override
public void onBackPressed()
{
Bundle extras = getIntent().getExtras();
boolean launchedFromWidget = false;
if (extras.containsKey("EXTRA_LAUNCHED_BY_WIDGET"))
{
launchedFromWidget = extras.getBoolean("EXTRA_LAUNCHED_BY_WIDGET");
}
if (launchedFromWidget)
{
// Launched from widget, handle as special case
}
else
{
// Not launched from widget, handle as normal
}
}