I have 4 Activities and my navigation is like this :
first activity --> second activity --> third activity --> fourth activity --> third activity
when I press back now from the 'third activity' , it goes to the fourth activity . However I want it to go to the second activity. So, I have overridden onBackPressed() method in third activity to : startActivity(this , SeconActivity.class)
Problem : When I first navigate from first activity --> second activity , I enable and disable buttons based on some inputs from the first activity in the onCreate() method. So, I want to preserve these changes when I navigate from third activity --> second activity . Any ideas ?
Start the 4th activity via a startActivityForResult. When you want to call the 3rd activity again, just return the results required to configure the 3rd activity as you want it to be, via an onActivityResults().
3rd activity psuedo-code:
final int FOURTH_RESULTS=101;
startActivityForResults(Intent fourthActivityIntent, FORTH_RESULTS
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (requestCode)
{
case FORTH_RESULTS:
//Do stuff here
break;
}
}
4th activity psuedo-code (Place this where you used to call the 3rd level)
Intent result = new Intent();
setResult(Activity.RESULT_OK, result);
See also the API.
Read about the activity launch modes for info on this subject, singleTop has worked for me in the past.
http://developer.android.com/guide/topics/manifest/activity-element.html
If you need to do complicated flows I recommend using this library
http://www.androidviews.net/2012/11/wizardpager/
It is a good way of enforcing a sort of flow into your android app.
Related
I've been struggling with a particular challenge which is as follows:
My app has an activity "A" which is considered the app's "main" activity. At a certain point, it launches an activity "B" which has an action available that should launch a fragment inside activity "A" (this won't always be the same fragment, it will depend on some data coming from our backend).
I can do this just fine by simply calling startActivity with the correct Intent, however, on pressing the back button, it goes back to A's "main fragment" (this is logic implemented inside of A's onBackButtonPressed()). Essentially, what should happen is as follows:
Activity A -> Activity B -> Activity A showing Fragment X -> press back -> Activity B
What happens when using startActivity to launch Activity A:
Activity A -> Activity B -> Activity A showing Fragment X -> press back -> Activity A showing the "main fragment". From here, if I press back again the app exits, which again is part of the implementation of A's onBackButtonPressed, however I've tried retrieving an extra from the intent which invoked A in order to conditionally bring back activity B but the Intent seemed to be empty of extras for reasons I can't figure out. I am sure I am correctly putting the extras in the Intent since activity A launches the correct fragment when invoked from B based on what I put there.
More things I've tried:
Launching the desired fragment directly from within B, however this way the fragment is not shown with the navigation bar that exists in A and seems to show the main contents of activity B behind the fragment's elements, which in user experience terms is undesirable.
Using the Intent.FLAG_ACTIVITY_REORDER_TO_FRONT flag, which seemed to make no difference whatsoever.
As this is part of my company's app which already has a decent degree of complexity, I'm not at liberty to provide you with useful code samples, and hopefully my description is sufficient for someone to aid me.
Additional information
targetApi="n"
Testing on Android 11
Activity A has launchMode "singleTask"
Activity B has launchMode "singleTop"
For the intended behavior:
Avoid using any launchMode, taskAffinity or activity flags, the default behavior is absolutely good for your requirements ("standard" is the default launch mode). So when you do the action in Activity B, a new instance of Activity A will be launched after putting B in backstack, which is the default behavior.
You should have a logic in Activity A's onBackPressed() such that: if the fragment X is visible, then it will exit the whole activity, otherwise it passes by calling super(). Something like the following:
In Activity A
#Override
public void onBackPressed() {
Fragment fragment = getFragmentManager().findFragmentByTag("yourTagForFragmentX");
if (fragment instanceof XFragment) {
// The fragment is available in the fragment manager
finish()
} else {
super.onBackPressed();
}
}
For more details, here
I think you're overcomplicating things.
Remove all of the launch mode flags for A and B - they should not be necessary.
Remove custom handling of onBackPressed - default handling should suffice.
Update A to initialize itself to the correct fragment based on the intent it's given:
For example:
onCreate(...) {
if (getIntent().getAction() == "START_ON_X") {
// Notice we REPLACE and DO NOT add to back stack
getFragmentManager().replace(fragID, createXFragment()).commit()
}
else {
getFragmentManager().replace(fragID, createDefaultFragment()).commit()
}
}
Thus, you will have:
Default launcher intent launches A.
A launches B.
B launches A with specific intent to show Fragment X
This will give you a stack of A -> B -> Ax
Then when you press back, DEFAULT BEHAVIOR will leave you on B.
Then pressing back again will leave you on A.
Then pressing back again will close your app.
Again this is all standard, default behavior. KISS.
Recently, I faced a problem to re-initiate Activity that's already in back-stack. The flag FLAG_ACTIVITY_REORDER_TO_FRONT is the best solution for manage this problem. But in Android 4.4 & later it isn't work well(some times Activity view is getting freezes or Application minimizes itself, menu isn't inflated to re-initiated Activity or Keyboard isn't allow to enter something to text area) but in previous versions this flag re-initiate's the Activity, and removed from back stack. Please review this link for more details.
In Android 4.4 & later, the application misbehaves when FLAG_ACTIVITY_REORDER_TO_FRONT flag is used in Activity creation. The major issues are, some times Activity is going to freeze state, when navigate to another activity key board isn't working well(key board is shown but user can't enter anything to text area), didn't inflate menu, or Application navigates to minimize state.
I think this issue is related to back-stack and flow of activity, when launcher activity(in my application, SplashScreenActivity is a launcher) finishes, then sub-activity causes some problem when using FLAG_ACTIVITY_REORDER_TO_FRONT to re-initiate previous Activity. So in this scenario, don't kill launcher or parent activity & start next activity using startActivityForResult(childAcivityIntent, requestcode), & kill parent activity at the time of onActivityResult call. And also remember don't use singleInstance or singleTop flags in child & parent activities.
private void onStartNextActivity() {
Intent mIntent= new Intent(SplashscreenActivity.this, ChildActivity.class);
mIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivityForResult(mIntent, 1111);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==1111)
finish();
}
I was also facing the same issue:
When I am coming back to the parent Activity by setting the Intent flag FLAG_ACTIVITY_REORDER_TO_FRONT from child activity, some times Application is minimized in Nexus5 with Android Marshmallow.
I struggled for 3 days and at last I change the Launch mode of activity to Single Task.
Now My application is working fine.
My Android app is for a hiking club and starts with a Home screen, which is the main activity.
The home screen shows the house-style and has some buttons to the core functionalities: list of upcoming hikes, history of hikes, last reactions and also a message board.
THe activity flow is pretty straightforward, you can i.e. navigate from:
Home -> Hike list -> Hike Details
And back using the Back button. Going back from the Home activity will ask for closing the app.
I already use the FLAG_ACTIVITY_CLEAR_TOP flag to prevent several instance of the same activity.
But my problem is I have also implemented a Menu to navigate to the core functionalities directly.
So for example, when in the Hike Detail screen, one can choose to go to the Message board. But I do not want to keep the Hike List -> Hike Detail activities on the stack.
So when pressing Back from the message board, I always want to return to the Home activity.
IS there a clean possibility to pop the stack and only keep the Home activity before launching a new activity? I guess that would solve my issue.
I found something similar on SO that might work.
Check out: FLAG_ACTIVITY_TASK_ON_HOME
Pre API 11:
Start all of your activities from home using startActivityForResult(). When you navigate to a parallel stack via the global menu. Call this on your current activity:
// startParallelActivity();
setResult(KILL_YOURSELF);
finish;
Where every activity on top of home implements onActivityResult() like so:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == KILL_YOURSELF) {
setResult(KILL_YOURSELF);
finish();
}
}
This will destroy all the activities in the current stack, leaving just the home activity that will be there when the user hits "back"
My application contains four tabs at the bottom.Each tab has multiple child activities.The flow may be like this,
Tab1--A-->B-->C-->D-->E
Tab2--X-->Y-->D-->E
Tab3--M
Tab4--P-->Q-->Y-->D-->E
My question is ,
when I am in C child activity of Tab1,and I press Tab2.Again when I come back to Tab1 ,it is in C child activity.But I want A activity to be restarted.can someone please give the solution by providing some sample code.Thank in advance
from your B activity, start C activity using method, startActivityForResult() and Override onActivityResult() method in all of them this way.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
finish();
}
Now at every Tab switch, you must call finish() at current active activty. that in turn will destory all activities and coming back to that tab will show you first activity.
Note that, you wont want to destroy your first activty. For this reason, you must start activity B from A using startActivity() and you donot need to Override onActivityResult() for A activity.
regards,
Aqif Hamid
My app starts up at Activity A which contains a ListView. The ListView can have items added to it if the user hits "Add" button and goes to Activity B.
In Activity B they fill out some forms and hit "OK" button which takes them back to Activity A where the new item is added to the ListView.
I have a finish() method after going from B to A -- but NOT the other way around.
So if you hit back three times after adding three items. It will just repeat the ListView (Activity A) over 3 times -- less one item that was added.
What is the best way in doing this? I can't put a finish method on the "Add" Button (going from A to B) because if you are in Activity B, it will close the app instead of taking you back to A -- which I do not want. That is, if the user changes his mind and doesn't want to "Add new item" by hitting "OK" while in B. Is a manual Back button the only answer?
Start Activity B by using startActivityForResult() and finish activity B after filling the form.
EDIT
When you startActivityForResult(), you pass 2 parameters, namely intent and requestcode. After you are finished with the new activity(in your case Activity B) you use a function setResult(RESULT_OK) to signify that the operation in Activity B was successful and then you call finish(). After the call to finish() the Activity B will return to Activity A and will call onActivityResult(int requestCode, int resultCode, Intent data). The parameter requestcode helps in identifying which particular activity/request has returned.
Hope this explanation helps you.