How does one navigate back more than one screen? - android

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();

Related

Back button from activity 2 closes down the app instead of going to activity 1 in Android 7

Pressing back button from the second activity returned to the first activity before without problems. I then updated to Android 7.
Then the whole app closed when pressing back button from the second activity.
I know that there are threads about this here and I have checked them all. Basically, they say that finish() should be avoided from the first activity.
I don't call finish(), so that is the problem here. It is difficult to solve, because it works like it should when I launch the app from Android studio.
It returns to the first activity from second. The problem occurs when the app is started by pressing its icon (not from Android studio).
Pressing back from the second activity closes down the whole app. How can I solve this? Here is some of my code:
Activity 1:
Intent glIntent = new Intent("astral.worldstriall.GLActivity");
glIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
The below code should be used in 2nd activity so that when u press back button it terminates the current activity(2nd activity) and goes back to previous activity
#Override
public void onBackPressed() {
super.onBackPressed();
finish();
}
I think you just misused the Intent constructor. According to the documentation, you used this constructor Intent(String action). The one that you atually want should be this one Intent(Context packageContext, Class<?> cls).
In the first activity (therefore this being the instance of your first activity), you should write:
Intent glIntent = new Intent(this, astral.worldstriall.GLActivity.class);
glIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(glIntent);
For going first to second activity...
Intent i=new Intent(FirstActivity.this,SecondActivity.class);
startActivity(i);
Use below code for going in previous activity...
#Override
public void onBackPressed() {
super.onBackPressed();
Intent i=new Intent(SecondActivity.this, FirstActivity.class);
startActivity(i);
}

Exclude Activity from recents and history

Actually I have a direct issue with android custom tabs.
But nevertheless I will generalize my question. Let's assume that I have ActivityA and ActivityB. ActivityA - is an external one, so that we launch it from an Intent :
Intent intent = customTabsIntent.intent;
intent.setData(requestUri);
intent.putExtra(CustomTabsIntent.EXTRA_TITLE_VISIBILITY_STATE, CustomTabsIntent.NO_TITLE);
mContext.startActivity(intent);
From here we see that ActivityA - is actually a custom tab activity. When things get done I launch ActivityB. I want ActivityA dissaper from task history, I can achieve this by aplying flag Intent.FLAG_ACTIVITY_NO_HISTORY to my intent. But this approach is causing problems, because when user switches to recents,or goes to other app - ActivityA disappears forever. Of course - that's how flag no history works. But I want a different flow, I want ActivityA disappear only when ActivityB was launched. Any ideas how to achieve this?
P.S. I need to finish ActivityA, which gets launched via intent, I don't have access to its code and I don't have the ability to call finish().
I don't think you can do this by using the NO_HISTORY flag since ActivityA is doing the launching and you have no control over it.
However, you should be able to achieve your goal (not being able to go from ActivityB back to ActivityA by overriding the BACK button in ActivityB and having it go back to whatever is underneath ActivityA in the task stack.
Assuming that ActivityC is the one that starts ActivityA, you could do something like this in ActivityB:
#Override
public void onBackPressed() {
// Direct user back to ActivityC
Intent intent = new Intent(this, ActivityC.class);
// Add flags to ensure that we reuse the existing instance of
// ActivityC and that we clear any other activities above ActivityC
// from the stack.
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
You can use finish() method to clear any activity. so before starting another activity finish that.
Intent intent = customTabsIntent.intent;
intent.setData(requestUri);
intent.putExtra(CustomTabsIntent.EXTRA_TITLE_VISIBILITY_STATE, CustomTabsIntent.NO_TITLE);
mContext.startActivity(intent);
finish(); //add this to clear that activity

Back button should quit directly

i have two main Activity with two separate XML file that design for two languages.
when someone tap on Image button on Main Activity ENG ,it will change and another activity with different layout and language shows up.
the point is, i have on Back Pressed() method that if user pressed back button twice , it should exit the app.
now what i get is when tap a lot and switch between two activity the back pressed button wants to back to previous activity to the end that it seems absolutely right but i need to quit directly. what can i do?
public void onBackPressed()
{
if(count == 1)
{
count=0;
finish();
}
else
{
Toast.makeText(getApplicationContext(), "Press Back again to quit.", Toast.LENGTH_SHORT).show();
count++;
super.onBackPressed();
}
return;
}
thanx
Simple scenario, You start Your Activity B from Activity A by button press:
yourButton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v){
Intent i = new Intent(YourActivity.this,YourNextActivity.class);
startActivity(i);
finish();//finish Your first activity
}
});
The only thing You have to do is, to finish the first Activity from where You get to the next one. Then Activity B has no chance to go back to Activity A and the app "finishs".
This is an article about exit and quit in android apps.
http://android.nextapp.com/site/fx/doc/exit
but for your app purposes you code use these lines:
finish();
moveTaskToBack(true);
System.exit(0);
This is the correct behaviour, to quit, you'd have to call finish() on both activities. However, if you create the second Activity with the Intent.FLAG_ACTIVITY_CLEAR_TOP flag, you'll be able to quit as described. However, your users won't be able to go back in the activity hierarchy - are you sure you want that?
Anyways, this way you'll be able to quit:
final Intent intent = new Intent(this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

Not to destroy current activity on back button is pressed

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);
}

Removing an activity from the history stack

My app shows a signup activity the first time the user runs the app, looks like:
ActivitySplashScreen (welcome to game, sign up for an account?)
ActivitySplashScreenSignUp (great, fill in this info)
ActivityGameMain (main game screen)
so the activities launch each other in exactly that order, when the user clicks through a button on each screen.
When the user goes from activity #2 to #3, is it possible to wipe #1 and #2 off the history stack completely? I'd like it so that if the user is at #3, and hits the back button, they just go to the homescreen, instead of back to the splash screen.
I think I can accomplish this with tasks (ie. start a new task on #3) but wanted to see if there was simpler method,
Thanks
You can achieve this by setting the android:noHistory attribute to "true" in the relevant <activity> entries in your AndroidManifest.xml file. For example:
<activity
android:name=".AnyActivity"
android:noHistory="true" />
You can use forwarding to remove the previous activity from the activity stack while launching the next one. There's an example of this in the APIDemos, but basically all you're doing is calling finish() immediately after calling startActivity().
Yes, have a look at Intent.FLAG_ACTIVITY_NO_HISTORY.
This is likely not the ideal way to do it. If someone has a better way, I will be looking forward to implementing it. Here's how I accomplished this specific task with pre-version-11 sdk.
in each class you want to go away when it's clear time, you need to do this:
... interesting code stuff ...
Intent i = new Intent(MyActivityThatNeedsToGo.this, NextActivity.class);
startActivityForResult(i, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == R.string.unwind_stack_result_id) {
this.setResult(R.string.unwind_stack_result_id);
this.finish();
}
}
then the one that needs to set off the chain of pops from the stack needs to just call this when you want to initiate it:
NextActivity.this.setResult(R.string.unwind_stack_result_id);
NextActivity.this.finish();
Then the activities aren't on the stack!
Remember folks, that you can start an activity, and then begin cleaning up behind it, execution does not follow a single (the ui) thread.
One way that works pre API 11 is to start ActivityGameMain first, then in the onCreate of that Activity start your ActivitySplashScreen activity. The ActivityGameMain won't appear as you call startActivity too soon for the splash.
Then you can clear the stack when starting ActivityGameMain by setting these flags on the Intent:
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
You also must add this to ActivitySplashScreen:
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
So that pressing back on that activity doesn't go back to your ActivityGameMain.
I assume you don't want the splash screen to be gone back to either, to achieve this I suggest setting it to noHistory in your AndroidManifest.xml. Then put the goBackPressed code in your ActivitySplashScreenSignUp class instead.
However I have found a few ways to break this. Start another app from a notification while ActivitySplashScreenSignUp is shown and the back history is not reset.
The only real way around this is in API 11:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
I use this way.
Intent i = new Intent(MyOldActivity.this, MyNewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);
I know I'm late on this (it's been two years since the question was asked) but I accomplished this by intercepting the back button press. Rather than checking for specific activities, I just look at the count and if it's less than 3 it simply sends the app to the back (pausing the app and returning the user to whatever was running before launch). I check for less than three because I only have one intro screen. Also, I check the count because my app allows the user to navigate back to the home screen through the menu, so this allows them to back up through other screens like normal if there are activities other than the intro screen on the stack.
//We want the home screen to behave like the bottom of the activity stack so we do not return to the initial screen
//unless the application has been killed. Users can toggle the session mode with a menu item at all other times.
#Override
public void onBackPressed() {
//Check the activity stack and see if it's more than two deep (initial screen and home screen)
//If it's more than two deep, then let the app proccess the press
ActivityManager am = (ActivityManager)this.getSystemService(Activity.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(3); //3 because we have to give it something. This is an arbitrary number
int activityCount = tasks.get(0).numActivities;
if (activityCount < 3)
{
moveTaskToBack(true);
}
else
{
super.onBackPressed();
}
}
In the manifest you can add:
android:noHistory="true"
<activity
android:name=".ActivityName"
android:noHistory="true" />
You can also call
finish()
immediately after calling startActivity(..)
Just set noHistory="true" in Manifest file.
It makes activity being removed from the backstack.
It is crazy that no one has mentioned this elegant solution. This should be the accepted answer.
SplashActivity -> AuthActivity -> DashActivity
if (!sessionManager.isLoggedIn()) {
Intent intent = new Intent(context, AuthActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
context.startActivity(intent);
finish();
} else {
Intent intent = new Intent(context, DashActivity.class);
context.startActivity(intent);
finish();
}
The key here is to use intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); for the intermediary Activity. Once that middle link is broken, the DashActivity will the first and last in the stack.
android:noHistory="true" is a bad solution, as it causes problems when relying on the Activity as a callback e.g onActivityResult. This is the recommended solution and should be accepted.
It's too late but hope it helps. Most of the answers are not pointing into the right direction. There are two simple flags for such thing.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
From Android docs:
public static final int FLAG_ACTIVITY_CLEAR_TASK
Added in API level 11
If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the
activity to be cleared before the activity is started. That is, the
activity becomes the new root of an otherwise empty task, and any old
activities are finished. This can only be used in conjunction with
FLAG_ACTIVITY_NEW_TASK.
Just call this.finish() before startActivity(intent) like this-
Intent intent = new Intent(ActivityOne.this, ActivityTwo.class);
this.finish();
startActivity(intent);
Removing a activity from a History is done By setting the flag before the activity You Don't want
A->B->C->D
Suppose A,B,C and D are 4 Activities if you want to clear B and C then
set flag
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
In the activity A and B
Here is the code bit
Intent intent = new Intent(this,Activity_B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
super.finishAndRemoveTask();
}
else {
super.finish();
}
Here I have listed few ways to accomplish this task:
Go to the manifest.xml- and put android:noHistory="true", to remove the activity from the stack.
While switching from present activity to some other activity, in intent set flag as (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK). It is demonstrated in the example below.
Intent intent = new Intent(CurrentActivity.this, HomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent);here
Note :Putting the intent flags can cause blank screen for sometime (while switching activity).
Try this:
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)
it is API Level 1, check the link.

Categories

Resources