In my Android application I'm trying to make sure that certain activity should be always placed at the root of backstack when navigating to it.
For example user starts A->B->C->D activities. Imaging that A - splash screen (with NoHistory = true), B - main page, C,D - some details pages. On details page (D) user has ability to go to the main activity (B). Having B-C-D backstack User press "Go To B" button and navigated to the existing home activity (B), same time C,D activities are stopped and destroyed. I'm using SingleInstance for my B activity and it works fine in this case.
I have case when this doesn't work for me. At the splash screen I can discover that I should skip main page and go directly to one of the details page (for example D). And here when I go to home page my backstack is wrong: D->B instead of just B.
What flags or attributes are more suitable in my case. May be it is more valid approach to update application navigation logic?
Thank you for any suggestions!
In A:
Intent intent = new Intent(B.class, this);
startActivity(intent);
finish(); //finish A behind you so you can only explicitly return to it
In B, two methods for the buttons, I guess, that get you to either C or D:
public void buttonToC(View view){
Intent intent = new Intent(C.class, this);
startActivity(intent);
}
public void buttonToD(View view){
Intent intent = new Intent(D.class, this);
startActivity(intent);
}
In C and D, you can optionally finish the Activity if you press back:
public void onBackPressed(){
Intent intent = new Intent(B.class, this);
startActivity(intent);
finish(); // optional
}
So A -> B and A finishes. From B -> C OR D but B is still running in the background. When in C or D, pressing back brings up the background activity, B. This should work.
Related
I've been trying the new Navigation component and so far so good. However, I've hit a wall when it comes to the following. My question is best described with an example, so let me give one.
I think it's a very common scenario that apps have a login screen and then they forward the user to a home screen, or dashboard, or something similar. Let's stick to the naming - LoginScreen and HomeScreen.
Say the app is very simple. It starts at the LoginScreen and as soon as the user logs in, they're forwarded to the HoneScreen. Pretty simple app, but serves the example.
Now, if the user hits back, how do we exit the app? So far it always takes me to the LoginScreen.
Further evolving on this example. Imagine there's a welcome screen before the login screen where the user can decide to login or register. How would one deal with navigating back in this case too?
Essentially, I'm asking if there's a built in functionality in the navigation component that let's you go back more than one screen and if not, is there a way to achieve this? Thank you very much.
#Fred
To achieve this you can finish each activity after having started the other one. For example the WelcomeScreen has called LoginScreen you can directly finish it and when LoginScreen calls HomeScreen finish LoginScreen so when the user will navigate back from HomeScreen all activities will be closed.
Or, from the present activity you can call System.exit(0) to exit the application. This serves when you have many activities but if you have one there will be no difference with finish()
Another scenario is as you described in comments:
Consider you have following activities: ActivityA, ActivityB and ActivityC and you want to come back to ActivityA from ActivityC without passing by ActivityB. If you ActivityA has been previously opened you can bring it back to front, depending on when you want this to be done. With our sample we consider when the activity finishes:
#Override
protected void onDestroy() {
super.onDestroy();
//this will bring the ActivityA on the front
Intent intent=new Intent(this,ActivityA.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
Or you may have a different scenario where the LoginActivity is started only if the is not already connected otherwise you do directly to HomeScreen. In this case, I create a Singleton that will help me register the current calling activity so that I can know which activity will be directly started after successful login.
For example:
if(sharedPreferences!=null) {
if (sharedPreferences.getBoolean("user_connected",false)){
startActivity(new Intent(this, HomeScreen.class));}
else
{
MySingleton.getInstance().setCurrentCallingActivity("HomeScreen");
startActivity(new Intent(this, LoginActivity.class));
}
}
And once in LoginActivity, after a successful login, I do the following:
try
{
startActivity(new Intent(this,
getClassLoader().loadClass(MySingleton.getInstance().getCurrentCallingActivity())));
finish();
}catch (ClassNotFoundException e)
{
//your code
finish();
}
That's how I handle that and it works. Up to you to see a corresponding scenario and try if it can work. Different approches may coexist and this far from being performant.
You could try this:
Intent myIntent = new Intent(LoginScreen.this, HomeScreen.class);
startActivity(myIntent);
finish(); //finish LoginScreen, then when press back in HomeScreen, it will exit instead return LoginScreen
First of all you need to see if u prefer to use Activity or Fragments.
if you want to remove all Fragments in the stack then you need to use
FragmentManager fms = getSupportFragmentManager();
for (int i = 0; i < fms.getBackStackEntryCount(); ++i) {
fms.popBackStack(); }
If you want to remove specifc Fragment than you will have to use tags.
Fragment fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if(fragment != null)
getSupportFragmentManager().beginTransaction().remove(fragment).commit();
Now about Activity you need to consider a few options
Activity A is your Login.
Activity B is your Register page.
Activity C is your Homepage.
if you want to move from A to C after Successful login than use
Intent intent = new Intent(Login.this, MainActivity.class);
startActivity(intent);
finish();
if you want to move from A to B
Intent intent = new Intent(Login.this, Register.class);
startActivity(intent);
if you want to move from A to B and after Register success move to C than use :
Intent intent = new Intent(LoginSM.this, MainActivitySM.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
I have A and B activities. A is singleTop on launch, B is excludeFromRecents. When I back from B to A, B is always destroying. How to prevent it? When I press Home then B is just stopped and not destoying. Thanks.
Following back code if B activity:
Intent intent = new Intent(this, ActivityPlaylist.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Without flags back not working at all.
I also have prevention of creating new instance in onCreate of A reason of I launch app from Eclipse (bug):
if (!isTaskRoot()) {
// Android launched another instance of the root activity into an existing task
// so just quietly finish and go away, dropping the user back into the activity
// at the top of the stack (ie: the last state of this task)
finish();
return;
}
Upd: my case is I need do not lose B condition, including list position and so on.
I have 3 activities in my application
ActA
ActB
ActC
Suppose I am in activity ActB and I am loading ActC with out finish(); ActB
Then when press a button in ActC , need to redirect the application to ActB . But this time when I press back from redirected ActB , another ActB ( previously loaded ) is showing.
Is there any way to kill all the activities which are previously loaded when we press the button in ActC ?
I am new to android and its ruining my time
Please help
thanks in advance
When you launch ActC from ActB, do so with this flag on the intent:
Intent intent = new Intent (this, ActB.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Javadoc:
"If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent."
Just going from ActB to ActC, use Intent and finish() after calling the Intent
Intent intent = new Intent(this, ActC.class);
startActivity(intent);
finish();
And then if you want to go back to B from C, then do the same in reverse, so switch
Intent intent = new Intent(this, ActB.class);
And the rest is the same.
Suppose you move like this
A -> B -> C
All the previous instances will be there in backstack for previous activities.
until and unless it is your requirement to create new instance of activity then only do so.
when you press button in you want to come to B but if you don't need new instance of B you can go with backstack item and according to me you should.
in button click you can simply call onBackPressed() of activity which is called when you press back button of device.
Also as Vee said you can use that flag to clear activities above your current activity.
If you want to "kill" the activity you should call finish();
To achieve your goal you can do the following thing.
When starting ActB from ActA, after calling startActivity(...); put finish();
This way you killed Activity A, do the same in ActB when calling ActC. Then when you call ActB from ActC again, it will start a completely new activity.
If you don't need a new instance of B then you can simply call finish() in your onClick() of C and this will take you back to B and no need for Intent or any other code.
If you need a new instance of B then you can use Vee's suggestion, keeping in mind that this will clear Activities off of the stack if you add more in between.
If you don't need a new instance of B but want to pass data back to it then you can use the flag FLAG_ACTIVITY_REORDER_TO_FRONT
Intent i = new Intent(ActC.this, ActB.class);
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
// can send data to ActB if needed with putExtras()
startActivity(i);
finish(); // if you want to destroy C and take it off the stack
this will not create a new instance of B but bring it to the top of the stack so when you press the "Back" button, you will not have the second instance on there.
When user presses button in ActC to goes back to ActB (by creating a new ActB) do this:
Intent intent = new Intent(this, ActB.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
This will finish both ActC and the previous ActB and create a new ActB.
I have two activities, A and B. I have a button in A,when pressed starts a new intent to B.
However whenever I press the back button while in B, than click the button again is restarts Activity.I do not want to do that,I want it to resume Activity B.
Actually I am doing some networking in Activity B and I want to save unless the user wants to refresh.
How can I do it? Thanks in advance
Use
#Override
public void onBackPressed(){
moveTaskToBack(true);
}
Hope, It must help you
You need to Overrider the
onBackPressed
method and start there the activity like this:
#Override
public void onBackPressed() {
Intent intent = new Intent(this, activityA.class);
startActivityForResult(intent, PICK_CONTACT_REQ);
}
This sounds like you need to rethink your architecture. You say:
Actually I am doing some networking in Activity B and I want to save
unless the user wants to refresh.
If this is the case, you probably don't want to do your networking in ActivityB. Maybe you should start a Service from ActivityB to do the networking. The service and the activity can communicate with each other so that the activity can keep the user up-to-date about the state of the networking. If the user presses BACK in ActivityB, it can finish (as usual) and return to ActivityA. In this case, the Service is still managing the networking. When the user again starts ActivityB (from ActivityA), the new instance of ActivityB can communicate with the service to see if there is any networking going on, and if so it can get the current status of that networking or start it or stop it or whatever.
I guess I'm too late but I had a similar problem.
I had two activities A,B and a next button in A.
Whenever I tried to do: A->press next button ->B->press back button->A->press next button->B, B screen got destroyed when I pressed the back button. So when I came back to B for the second time it was a newly created B (all the information I had put in was gone).
So it was like A->B->A->new B when I just wanted to go back to the original B! :(
So what I did was, in activity B, I overrode the onBackPressed() function so it doesn't destroy the activity. I also set the flag so that if there is a A activity already running, it would just pull it up to the front instead of creating a new A activity.
#Override
public void onBackPressed() {
Intent intent = new Intent(getApplicationContext(), ActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
Then, for the onclicklistener function for the next button in activity A, I set the flags similarly.
public void onClickNextbutton(View v){
Intent intent = new Intent(getApplicationContext(), ActivityB.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
I have got 4 activity let it be A->B->C->D.In every A,B,C activity user need to enter data all data will sent to server in C activity if the user data is correct he will move on to D activity and all the activity A,B,C removed from stack.If the data is in correct i need give the user to reenter data i.e is on back press it has to move C->B->A.My question is How to remove A,B,C activity when user enter D activity.
Use FLAG_ACTIVITY_CLEAR_TOP this shall solve your problem
From the Android documentation:
If set, and the activity being launched is already running in the
current task, then instead of launching a new instance of that
activity, all of the other activities on top of it will be closed and
this Intent will be delivered to the (now on top) old activity as a
new Intent.
For example, consider a task consisting of the activities: A, B, C, D.
If D calls startActivity() with an Intent that resolves to the
component of activity B, then C and D will be finished and B receive
the given Intent, resulting in the stack now being: A, B.
Use it like
Intent intent = new Intent(getApplicationContext(),
yourActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
and also, take a look at this question:
Activity with Flag FLAG_ACTIVITY_CLEAR_TOP (android)
Edit : I thought you want to move to your home activity from D and want to remove all activities from stack
Your stack would be like homeactivity , A , B , C , D
so i gave you this solution as this shall remove all activities in stack on top of your home activity.
If you want to clear the the stack while going to D, for that you can use FLAG_ACTIVITY_TASK_ON_HOME or FLAG_ACTIVITY_CLEAR_TASK
But both of these for api level 11.
The correct answer interesting for me also, but I can offer a solution:
For example you start activity A from O: O->A->B->C->D.
On activity O you can put in android manifest android:launchMode="singleTop"
Then, when data are ok, you can start activity O with flag "FLAG_ACTIVITY_CLEAR_TOP" - it remove from stack A,B,C and will be called method onNewIntent (Intent intent) http://developer.android.com/reference/android/app/Activity.html#onNewIntent(android.content.Intent) in O, where you can start activity D.
You can start activities with startActivityForResult, and call setResult from for example activity D, in C activity you can listen activity result, and related of this result finish activity or not, or call setResalt from C activity ...
When you want to move D activity there you need to check your
conditions and if your condition is satisfied then you need to enter
into your Next activity(i.e., D) .In that case you need to use the
following code..
Intent intent = new Intent(this,D.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
Suppose In on backpress you need to use finish(). to move back i.e., C
-> B -> A.
Try this piece of code with some modifications:
Intent intent = new Intent(this, D.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // To clean up all activities
startActivity(intent);
Try looking for Activity's public method startActivity(Intent i) and finish() here
In usage wise, it should look like this.
Intent i = new Intent(MainActivity.this, MainActivity.class);
startActivity(i);
finish();
Hope this helps :D