I'm working on an Android application that has 4 activities :
A -> B -> C -> D
When I'm going from A to B, from B to C, or from C to D, I put some extras in the Intent.
I guess navigation for something like that is quite simple: there's no need to redefine the back button, and for the "up" action bar button, a simple "finish()" would be to correct way to do it (?)
Now, the problem is that from A, I can also go directly to D. Still no need to redefine the back button, it will go back to A, and that's what I want, but for the "up" button, it must go to C, and from C, up will lead to B, ...
What is the correct way to do that?
Thanks for your answers
To control the flow between the various activities explicitly, I call finish() in each activity when I respond to user input by starting a new activity:
startActivity(intentForNewActivity);
finish();
That leads to that instance of the orignal Activity being destroyed. In each activity I create an Intent to start up the activity I want to go back to. Then write:
#Override public void onBackPressed() {
startActivity(intentWhereIWantToGoNext);
finish();
}
I originally wrote here that I called finish() in onStop(), which does work while the app remains running, but does not give the desired result if the app is stopped for any reason. Sorry for the confusion, and thanks to PravinCG, who, while his comments were not entirely on the right track, at least made me think more carefully.
One of the way is to actually have the same stack but use extras to perform the toggle.
For Instance: When you want to go from A -> D
go from A->B->C->D and use intents to handle whether you want to simply bypass activity or display it. Same is the case in reverse order user resultIntent for that.
Place the following code before the last bracket.
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
finish();
}
Related
I have an app with some normal behaviour but I still dont know what I am doing wrong.
Activity A calls --> Activity B
I pass strings/ints from one activity to the other (Intent.putExtra())
I had declared my activities as single instances and declared who is parent of who in my manifest, but when I open other app and then go back to mine, the activity I was in is the only still alive.
If I remove the'singleInstance', then my navigation works but the ones that receive strings from the intent (previous activity) crashes.
I want to be able to:
When I am in my app, navigate up/back through my activities.
If I leave my app and come back, still be able to navigate up/back in my app.
Considering I pass values between activities with Intent.putExtra("key", "value")
I think is all related with the Back/Up Navigation and the android:launchMode=["multiple" | "singleTop" | "singleTask" | "singleInstance"] but I can't find the perfect solution.
Update:
A --> B --> C
A->B: A putExtra; B getExtra
B->C: B put Extra; C get extra
If I go to C, leave the App and then come back to the app, the app is in C, and if I try to navigate up to B, it crashes because I don't have the extras and the activity has been terminated.
What is the best behaviour? Keep them open? Recreate them?
the behaviour you're trying to achieve is the default behaviour on Android. So I believe that on your question, less is more.
AndroidManifest.xml:
remove all parentActivityName from it. It really does not much at all.
remove all launchMode those specific edge cases, unless you have a specific reason and a non-default behaviour, do not use them.
intent parameters you're passing to activities don't get messed by any of those manifest details, I don't think they have anything to do with your issue. On any activity you should be able to call getIntent().getExtras() and access any parameters passed to it, no matter how many times you exit and enter the app.
you do not need to save/restore the intent parameters during onSaveInstanceState and onRestoreInstanceState. Those callbacks are for current state, not for parameters passed to it. Those are different things.
back: that happens automatically. You cannot finish(); the previous activity when calling the next one.
up: it's just a matter of overriding the onOptionsItemSelected
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
finish(); // this finishes and the previous will be shown.
return;
// other menu items ?
}
}
if I try to navigate up to B, it crashes because I don't have the
extras and the activity has been terminated. What is the best
behaviour? Keep them open? Recreate them?
do NEVER say "it crashes" on StackOverflow without providing a stacktrace and the lines of code around that stacktrace. That's one of the main reasons I downvote people.
If it crashes, ask about that crash, do not mess-up the automatically-default navigation to "try to fix it"
If i understand you must set condition in second activity example on String data:
if(intent != null){
yourString = intent.getStringExtra("count");
}
then you must provide saving instance like
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("count", yourString);//or int or other look on developers
}
and restoring from instance
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
yourString = savedInstanceState.getString("count");
}
http://developer.android.com/design/patterns/navigation.html
The up button takes you to the previous activity hierarchically in the same app.
The back button takes you to the previous screen/app/activity that your phone was on, irregardless of which app it belonged to.
I have three activities: A, B, C.
Activity A can start B or C.
When A starts C i can return to A just have pressed back button. But i want "return" to B and then to A (with second press of back button).
I tried to use TaskBackStack in this way:
final TaskStackBuilder builder = TaskStackBuilder.create(this)
.addParentStack(this)
.addNextIntent(new Intent(this, B.class))
.addNextIntent(new Intent(this, C.class));
builder.startActivities();
But its not working... Can anyone help me?
Sorry for my English and thanks in advance
Override onBackPressed method in your activity C.
#Override
public void onBackPressed() {
super.onBackPressed();
//finish();
Intent intent = new Intent(ActivityC.this,ActivityB.class);
startActivity(intent);
}
If you write finish you can go to Activity A because you came from Activity A. That's why use intents. Like that in Activity B also.
#Override
public void onBackPressed() {
super.onBackPressed();
//finish();
Intent intent = new Intent(ActivityB.this,ActivityA.class);
startActivity(intent);
}
Let me know the status?
Override your onKeyDown method
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//Do stuff, like launching a new activity
return true;
}
return super.onKeyDown(keyCode, event);
}
Before try to answer you question I have some comments about your approach to navigate between your activitys. In general, this approach is not a good idea, because doing that, you are not following the Android Navigation Pattern, and this can make your application not user friendly, since most Android Application use the Navigation Pattern.
The Android Navigation Pattern says:
Temporal navigation, or navigation between historical screens, is deeply rooted in the Android system. All Android users expect the Back button to take them to the previous screen, regardless of other state. The set of historical screens is always rooted at the user's Launcher application (the phone's "home" screen). That is, pressing Back enough times should land you back at the Launcher, after which the Back button will do nothing.
However, there is another possiblite to Navigate in your application using The Android Pattern, but I believe that is not a solution for your problem. You can take a look at Up Navigation
To finalize, I have a relevant comment about solution that uses override the OnBackPressed() to Start a new Activity. You should really avoid that, because using it, you will can make crazy your chronologic navigation. Because when you create an activity inside the OnBackPressed, you are always putting a new activity on Android Stack, so there are two problems here:
The stack can grow quickly depending of the user behavior
Can be hard get out of your applcaiton (Can be very hard to make your stack become empty)
go to this start basic with Activity Lifecycle. you ll have better knowledge of doing this. Go to this Calling one Activity from another in Android. you ll find many examples on google. try it.. one of the example.
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 intend to start 3 activities in a chain (like from main open Activities A, B and then C, which will be visible for the user), but I wasn't able to find some way how to do that in Android. Do not ask me why, I just have to do that for restoring my application state, where is was before.
Thanks for any ideas
Waypoint
Edit:
Ok, I have tried opening activities in For cycle, but they aren't opened properly. They are chained, but recreated only when I press back button and they display to me. I need some solution which leads to: open A, if A is opened check if needs to open B -> YES, open B, check if needs to open C -> YES, open C, no need to open another activity -> FINISH
prior to start any activity , decide which activity should be start .
Lets take your case >>first check for B , if yes check for C , now open the required 1 .
i understand comparable data is inside the activities, but a right data structure will always allow you to access the data wherever and whenever it actually requires .
For future readers: if you want to start activity with proper back stack, you should use TaskStackBuilder.
define the natural hierarchy for your activities by adding the android:parentActivityName attribute to each element in your app manifest file
create an instance of TaskStackBuilder and call addNextIntentWithParentStack(), passing it the Intent for the activity you want to start.
For more details see official documentation
Override the onResume-method in each activity. Add the check and the start of the activity there.
public void onResume() {
if( condition )
startActivity( intentForTheNextActivity );
}
Where condition is whatever condition you might have (in your example if B should be started, C should be started etc.) and intentForTheNextActivity is the intent for the following activity in the chain (e.g. if now in A, the intent is for B etc.).
I'm having a very hard time understanding exactly what it is you're trying to do. Sometimes it seems like it's a chain (A opens B, B opens C and so forth) sometimes it seems you want some random flow (A opens B, B opens A, A opens B, B opens C) - which makes it really hard to give you a specific answer.
What I can do, is recommend that you read up on the following:
Activity Lifecycle
Starting Activities and getting results (in particular the methods startActivityForResult and setResult)
If you need more help than this - you need to explain yourself better (maybe with a diagram or some sample code of what you have tried so far).
You didn't provide any information of what you've tried, so i'll give you the simplest answer:
method startActivity(Intent intent), more info here.
Edit: Hmm, how about this? I don't have SDK around me now, but i can provide a concept. I'm not sure if it works, but i hope it'll guide you to soultion.
Let's imagine this is ActivityA's code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (doINeedActivityB) {
Intent activityC = new Intent(this, ActivityC.class);
this.startActivity(activityA);
}
if (doINeedActivityC) {
Intent activityC = new Intent(this, ActivityC.class);
this.startActivity(activityC);
}
}
Right now an activity gets destroyed when the BACK key is pressed. How can I make it just stop ( i.e. keep all the variables, etc. alive ), rather then be destroyed?
Thanks!
Why is it that you need to keep the variables alive? Given the established lifecycle of an Android application, I'm not sure that preventing the activity from being destroyed "just to keep the variables" makes sense.
Even if you stop the application without destroying it, there is always the chance that Android will kill it to free up memory. You will have to account for this in your code anyway, and so preventing the application from destroying doesn't save you from writing code.
Variables can be saved and restored relatively easily and quickly using SharedPreferences in your onPause() and onResume() methods. Unless you are storing a ton of data, preventing the application from destroying might not make much of a difference.
It sounds like you want to keep the variables in memory because you intend to return to this activity. Typically, you don't use the back button to navigate away from activities that you intend to come back to. Instead you would create an Intent and start a new activity. When you do this, Android places the current activity on the Back Stack calling onPause() and onStop(), which seems like exactly the sort of behavior you are looking for.
So if you still really want to prevent your activity from being destroyed (at least until Android decides it's using too much memory and kills it on it's own) you could always use Sagar's code and start a new activity in onBackPressed().
#Override
public void onBackPressed()
{
Intent intent = new Intent(this, Other.class);
startActivity(intent);
}
Just be certain that that is what you really want to do.
Simple one line
#Override
public void onBackPressed() {
mActivity.moveTaskToBack(true);
}
Pressing the BACK key triggers the onBackPressed callback method of Activity class. The default implementation of this callback calls the finish() method.
http://developer.android.com/reference/android/app/Activity.html#onBackPressed()
You can override this method to move the activity to background (mimick the action of pressing the HOME key.
eg:
#Override
public void onBackPressed() {
onKeyDown(KeyEvent.KEYCODE_HOME);
}
You could also instead consider moveTaskToBackground() mentioned here:
Override back button to act like home button
I have managed to work out exactly what you want: switch between 2 activities using Back button and keep them all not to be destroyed!
For example: you have 2 activities A & B. A will be started first, then A calls B. When B is loaded, user press Back button and switches back to activity A from B. From now B should not be destroyed and just goes to background, and when user starts activity B from A again, activity B will be brought to foreground, instead of being re-created again or created new instance! How to implement this:
1. Override onBackPressed() of activity B:
#Override
public void onBackPressed() {
Intent backIntent = new Intent(this, ActivityA.class);
backIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(backIntent);
}
2. On activity A, call activity B:
public void callActivityB() {
Intent toBintent = new Intent(this, ActivityB.class);
toBIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(toBintent);
}
remember to add flag: Intent.FLAG_ACTIVITY_REORDER_TO_FRONT when you call A&B.
This is similar to this question that was asked earlier.
Hope this helps!
N.S.
First of all, sorry for not answering the question, cause, I still have no optimal answer for it.
But, I really like when people start asking "what do you need this for". And, very rarely, the person who asked the question, really deserves this kind of question. I think not this time, but ok, this is not the issue...
Anyway, I will try to point out why some of us are convinced that
going from Activity A to Activity B(creating UI based on some data fetching) AND
going back from B to A(destroying all the created UI and/or fetched data in B) is sometimes a bad concept. Better solution would be to keep the stack as it is, so using something like finish() in Activity B, but keeping the Activity B in Pause state, so later when calling it again from Activity A - it just goes in onResume = nothing recreated in UI, no additional data fetching. The bonus of course is a fast and responsive UI, and the difference is really if you have a more complicated UI layout.
Just specify in the manifest for the activity as
android:persistent="true"
That should prevent your activity getting destroyed. To know more about this please refer to these below links which were answered by me
How to prevent call of onDestroy() after onPause()?
Prevent activity from being destroyed as long as possible
In the above posts I have explained in detail with a use case