In my app, I start an eight step "wizard" from my landing page in which data is passed from step 1 all the way to step 8. For keeping the data intact while still in between steps, I am not calling finish() on either of the activities. However, when all the steps are complete, is there a way that I can close all the 8 activities I had started and return back to the landing page?
An illustration of sorts here:
Home - Step 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
At this point, when the user clicks "Save", close all the Steps (8) and go back to the Home Page. I have been creating a new intent to do this so far, but i realize this is not the best solution. A simple back press takes him back to the 7th Step.
Any help appreciated.
Intent intent = new Intent(this, Home.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
This will kill all the activities in between from your 8th screen and launch your hom screen back. also u can set ur home screen's acitivty in manifest launchmode="singleTop". see this link - developer.android.com/guide/topics/fundamentals.html#acttask
Another approach would be to use StartActivityForResult(...) to start each activity, and have activities call setResult() before finish(). Then in each Activity's onActivityResult(...) method call finish() if the intent is non-null.
This will create the full stack, and automatically chain-finish them all when the last finishes.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data == null) {
return; // back button, resume this activity
}
// Propagate result down the stack.
setResult(0, data);
finish();
}
This gives you a little more control and lets the original activity receive the result via onActivityResult rather than the create intent, which might be more intuitive if the original request has other state you want to preserve (in its start intent, in particular).
Related
I read many threads about this subject, but I couldn't find anything that fits my needs.
I have an application with 3 activities (I'll call them screens here, more intuitive): A (MainActivity), B and C.
Screen A starts another process, retrieves some information from that process and sets the layout according to the answer. Then it gives you the opportunity to do something (write a text). This is done on OnCreate().
Screen B is not very interesting (presents the text and allows you to edit it).
Screen C has a single button which exits the application (basically starts the home activity). C also closes the process we started on A (after communicating some info to it).
So far so good.
The problem is that when I restart my app, I see screen C again. This is not good for me, because I want the user to be able to edit the text, without having to go back to the first or second screen (not because it's so difficult, but because I need him to see the new info presented on screen A before he does anything. And this can't be done after C, because after C he's done, unless he decides to start the app again).
This means that when I get to screen C and press the button, my app is completed and there's nothing left for me to do there (but start over fresh). But if my app was suspended on screen B, there's no need to start fresh - I can just go back to it and continue from there (regular Android behavior).
So I set android:clearTaskOnLaunch="true"but now I have two problems:
1. It now starts fresh again (sort of, see #2) even if the app was suspended on B, which is not what I need.
2. It's not really starting fresh.... Yes, I see screen A. But all the things I did on OnCreate() are not done again, which means my other process is not up and running, and then my app crashes because I have no one to talk to.....
Is there any solution to such cases?
I need to start fresh (but really fresh, with all the things I did on OnCreate() done again) only after previous run of the application was completed (we pressed the single button on screen C and got back to the home screen).
In any other case of suspension (in A, B, and even C if we didn't press the button yet) I want the normal Android behavior (i.e. go back to the same screen).
Any help will be much appreciated.
To solve this you can take advantage of the Android Activity Lifecycle: http://developer.android.com/training/basics/activity-lifecycle/stopping.html
Simply call finish() in Activity B and C in onStop() or onPause() appropriately to wipe away those activities (or "screens" as you say) when the app is closed. Activity A should reopen holding the last state when you open your app back up.
If you're looking to wipe out the last state in Activity A as well, then add a finish() call to it as well where appropriate (probably onStop or onPause again per your use case)
Good luck!
I had a similar app before, a survey app, and had the same situation. A->B->C and once you finish C you go straight to A and can't go back but you can go back from B->A. Here what I did:
1) Add this to A Activity when you start B Activity:
Intent start;
start = new Intent(MainActivity.this, RecordName.class);
startActivityForResult(start, 2);
and this method in your A activity:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 2) {
if(resultCode == RESULT_OK){
//String result=data.getStringExtra("result");
finish();
}
}
2) In B Activity add this when you start C Activity:
Intent start;
start = new Intent(B.this, C.class);
startActivityForResult(start,1);
and this again in your B activity:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if(resultCode == RESULT_OK){
//String result=data.getStringExtra("result");
finish();
}
}
3) In your C activity add this to your press method:
Intent start;
start = new Intent(C.this,A.class);
// pass any data back to A activity
start.putExtra("Key", String);
startActivity(start);
// to close previous activities
Intent returnIntent = new Intent();
//returnIntent.putExtra("result","finish");
setResult(RESULT_OK,returnIntent);
// close current activity
finish();
I hope this helps
The functionality I want to model in my Android app is, that if the user does login, he gets forwarded to the main menu (MainMenuActivity). From here and everywhere else where I provide a button for it in the app, he must be able to logout, which should send him back to the login screen (LoginActivity) and finish all the activities above on the stack. I achieve this by not destroying the LoginActivity after a login and at logout calling:
Intent intent = new Intent(this, LoginActivity.class);
// Clean up all other activities.
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Also I want that the user can not go back with the backbutton form the main menu to the loginscreen. So I did overwrite the method onBackPressed() in my MainMenuActivity. Instead I want that when the user is pressing the backbutton from the main menu, the app does terminate (just like its the last activity on the stack). How can I achieve this?
I did read about several other approaches, for example finishing the LoginActivity after the login was performed and then later do it like described here:
https://stackoverflow.com/a/3008684/1332314
But I'm not quite sure if this is a proper solution, just read the comments below the post.
use this flag when you move to MainMenuActivity:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
this will delete all the previous activity and if you press back app will be closed.
Now in case of logout button do the same thing when you move to LoginActivity same flag will now make LoginActivity as the only activity on the stack and on back app will be closed.
Apparently I did find a solution to my problem. I just start the MainMenuActivity from the LoginActivity like this:
private void continueToMainMenu() {
Intent intent = new Intent(this, MainMenuActivity.class);
startActivityForResult(intent, 0);
}
Then, when the user presses the backbutton in the main menu, this overwritten function gets called:
public void onBackPressed() {
setResult(LoginActivity.ACTION_QUIT);
finish();
}
This will at first set a resultcode for the LoginScreen and then finish the MainMenuActivity. Then the LoginActivity does terminate receiving this particular resultcode, which I implemented like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == LoginActivity.ACTION_QUIT)
{
finish();
}
}
Doing it this way will ensure not to touch too deep into the activity lifecycles, all the callbacks to clean up will still be called and it should not open any security leaks.
Hope this helps if anyone else will bump into the same issue.
There are a lot of questions out there on similar topics, but after searching around I haven't found one that matches my issue.
I know about starting intents for result, and overriding onActivityResult() to handle these intents, but for some reason, I'm having issues when I'm coming back from activity b to activity a. So, for example, in the last of 3 activities (AddDirections class) I start in my project, I call this method to return back to the previous activity:
public void finish(View v){
Intent intent = new Intent(getApplicationContext(), AddIngredients.class);
intent.putExtra(Home.RECIPE_INTENT, (Parcelable)recipe);
intent.putExtra(Home.RECIPE_ID_INTENT, recipe.getId());
setResult(RESULT_OK, intent);
finish();
}
In the AddIngredients class, I have this method:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK && requestCode == DIRECTIONS_REQUEST){
Intent intent = new Intent(getApplicationContext(), NameRecipe.class);
Recipe recipe = data.getParcelableExtra(Home.RECIPE_INTENT);
intent.putExtra(Home.RECIPE_INTENT, (Parcelable)recipe);
setResult(RESULT_OK, intent);
finish();
}
}
This should accept the returned result from the AddDirections class, and pass it off to NameRecipe, where I have the exact same method (Except for in the new Intent method it says Home.class). In the Home class, I have basically the same method again to receive the intent as it backs all the way out of the app.
Now, I will say that this works if I go straight through the steps from beginning to end. But if I use the up navigation to go the current activity's parent activity, then it messes everything up. Then when I click finish in the final step it messes up the resultCodes that I set for each intent. I make sure to explicitly set the correct result to RESULT_OK (which equals 1) but then for some reason, sometimes it changes what I've set to be the resultCode to be 0 instead.
Here's what I do in an activity if the user clicks the up navigation:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent intent = NavUtils.getParentActivityIntent(this);
intent.putExtra(Home.RECIPE_INTENT, (Parcelable)recipe);
setResult(RESULT_OK, intent);
NavUtils.navigateUpTo(this, intent);
finish(); //Have tried with and without this
return true;
}
return super.onOptionsItemSelected(item);
}
Like I said, I've searched for a lot of reasons why the resultCode gets overwritten after using the up navigation, but I haven't found a single reason why.
Any help would be greatly appreciated.
It looks like the underlying question is really how do I navigate between multiple activities through the stack using the up navigation that is built in. I am wondering if the project is setup correctly for this type of navigation. From the android developer resources, up navigation from google, you have to setup the navigation buttons with a parent activity. Then the application can traverse between the different activities. From what it looks like this should allow A->B B->C c->D and back to A if needed. I would also add in a button that would allow a direct path back to A if the user so chooses.
If you have more information on what you are trying to accomplish between activities whether it is data passed back and forth or just returning to the previous activity that would be helpful. Hopefully the link will help your issue with this.
your problem seems to be the NavUp, this util class tends to clear everything to navigate to the parent including your resultCode and the instance of the activity, resulting in a Canceled result (if started for result) to a new instance of the parent activity, in order to fix that a quick fix would be to declare android:launchMode="singleTop" in your manifest, but I wouldn't recommend to use that unless you are 100% that you want that, instead I would go into my navigator class, or my method for navigate and overwrite that specific navigation to something like:
Intent parentActivityIntent = NavUtils.getParentActivityIntent(this);
parentActivityIntent.setFlags(
Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP
);
NavUtils.navigateUpTo(this, parentActivityIntent);
Hope this helps!!
Sorry for the late answer :p
if by 'up navigation' you mean back key pressed then you need to override a function
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
}
if from what it seems to be you are trying to get back when clicking an item from the Options Menu to your parent activity directly then i think you will need to go back step by step as at this moment there is already an activity running and waiting for a result so when you go directly to home activity its already waiting an answer from activity B and not activity C i hope i explained it right :)
This is my first post, so please be nice :)
I have a question and no one gave the answer in the post I've seen.
My app has a list and a button to open an activity, this activity creates a new item to show in the list of the previous activity when pressing the button Create.
How can I do this?
This is the code I made for the first button:
intent = new Intent(this.getBaseContext(), NewTestActivity.class);
this.finish();
startActivity(intent);
and this is the code to go back an refresh:
Intent intent = new Intent(getBaseContext(), TestListActivity.class);
startActivity(intent);
But the code to goback is useful, because the activity don't refresh.
I have to call the new activity in a diferent way? Or go back to previus activity in a diferent way? Or go back normally and refresh the activity when I'm back in the previus activity?
Well...this is all.
Sorry for my bad english and, if this question has been answered in another thread, give me the link to read, because I can't find it :)
PS: I started with android in December.
Thanks for your help.
When you are going to start new activity you shouldn't close a current one until you actually need this behaviour. (remove this.finish(); row from your code)
Also you shouldn't close an active activity manually until you actually need it. When the user presses the "back" button on the device Android pops the previous activity from the "back stack". Read once more Activity documentation.
According to your description you have a list of elements. So in order to refresh the list you need to update your dataset and notify the list about it by ListView.notifyDataSetChanged() method call.
Before getting to a real answer, I'd like to show some improvements to your code.
First, when creating an Intent (or when you need a context in general) from an Activity there is no need to call getBaseContext(), you can just use this:
intent = new Intent(this, NewTestActivity.class);
Second, android is good at handling Activities, you do not have to close your first activity manually with finish(). Android will automatically pause or stop your first activity and bring it back when you return to it.
Third, in your case you might want to use startActivityForResult() instead of startActivity() for reasons I will explain below.
This will make your code look like the following:
private static final int MY_REQUEST_CODE = 33487689; //put this at the top of your Activity-class, with any unique value.
intent = new Intent(this, NewTestActivity.class);
startActivityForResult(intent, MY_REQUEST_CODE);
Now, the startActivityForResult() starts an activity and waits for a result from that new Activity. When you call finsih() in the new Activity you will end up in the first Activitys onActivityResult()-method, with data supplied from the new Activty that is now closed:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode != MY_REQUEST_CODE) return; //We got a result from another request, so for this example we can return.
if(resultCode != RESULT_OK) return; //The user aborted the action, so we won't get any data.
//After the above if-statements we know that the activity that gives us a result was requested with the correct request code, and it's action was successful, we can begin extracting the data, which is in the data-intent:
Item item = (Item) data.getSerializableExtra("customData"); //casts the data object to the custom Item-class. This can be any class, as long as it is serializable. There are many other kinds of data that can be put into an intent, but for this example a serializable was used.
itemList.add(item); //This is the list that was specified in onCreate()
//If you use an Adapter, this is the place to call notifyDataSetChanged();
}
For this all to work, we need to do some things in the second Activity:
When the item has been created, we must set a result:
//We begin by packing our item in an Intent (the Item class is an example that is expected to implement Serializable)
Item theCreatedItem; //This is what was created in the activity
Intent data = new Intent();
data.putSerializable(theCreatedItem);
setResult(RESULT_OK, data);
finish();
This should return to the first Activitys onActivityResult()-method with the item, as explained above.
Assume that the application has two activities, namely Activity1 and Activity2.
Activity1 is responsible to load some bunch of text and audio files. During the loading process Activity1 disposes progress dialog. After successfully loading, then comes the Activity2.
In my application Activity1 must run only once. If the user presses back button on Activity2,then application must terminate. But what I have seen that, Activity1 comes to the screen if the back button is pressed.
How can I achieve this? Is there any way to terminate application in the case of user presses back button on Activity2?
Any help will be appreciated.
Thanks
You could just have finish() after you start intent for Activity2.
Intent intent = new Intent(this, Activity2.class);
startActivity(intent);
finish();
Your could override onActivityResult in Activty1 which will be called when Activity2 exits and returns control to it.
Then something like:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
finish();
}
Should close activity1 after activity2 is closed.