Activity Flows A->B->C->A in android - android

Suppose I have 3 activities: A, B and C.
A: Home Activity
B: Information gather Activity
C: Information display Activity
My desired flow goes like:
A triggers B to gather information.
When B ends, C will get the information and display.
A->B->C->A.
When C ends, it should go back to A. (this is never a problem as I will B: finish())
My first attempt: (Failed due to I do not want to see the A after B, even for few miliseconds)
A triggers B to gather information. (startActivityAsResult)
B pass result to A, and B :finish(). (onActivityResult)
Then A triggers C to display. (startActivity)
My second attempt: (Succeed but I'm thinking is there a better way despite this?)
A triggers B to gather information. (startActivity)
B triggers C, and B :finish(). (startActivity)
Questions:
Is there any alternative way (which is simpler/direct) of defining the sequence of navigation flows like i see taskBuilder with nextIntent() API?

In Activity C on back button press clear the backstack and navigate to A
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackPressed();
}
return super.onKeyDown(keyCode, event);
}
public void onBackPressed() {
Intent myIntent = new Intent(C.this,A.class);
myIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);// clear the backstack
startActivity(myIntent);
finish();
return;
}
A to B To C
In your activity back stack you will have C at the top, next B and next A.
When you press back button in C, activity C is popped from stack, destroyed and the previous activity B takes focus. So if you wish to navigate to A from C ,clear the back stack , navigate to A and finish the current activity.

If I understand you correctly, you just want to make it impossible for the user to use the back button to get into activities that have already been "used up," yes? Try modifying the activity tags in your AndroidManifest.xml using something like the following:
<activity
android:name="yourpackagename.yourappname.YourActivity"
android:label="#string/your_app_title"
android:noHistory="true" >
Once you add the noHistory attribute, the activity in question is yanked from the activity history, and you'll be able to force your user to go only forwards as your intents describe.

Related

How to detect if a parent activity is in the back stack and can go up without creating a new instance?

I have a system which has several Activity, Activity X, Activity A, Activity B, and Activity Y. Activity X consist of list of A. If we click on A, it will go to Activity A. Activity A consist of list of B. If we click on B, it will go to Activity B. Activity B will also consist of list of B. So, if we click B on Activity B, it will go to Activity B. It is possible to end up the stack like this: X -> A -> B -> B -> B -> B -> B. According to proper navigation by Android, if we click Up on Activity B, it should go to Activity A, no matter how deep the stack is. So, every B on the previous stack should end up on A. Up until now, it's simple. I just need to set the parent class of Activity B as Activity A.
The problem is I can go to Activity B from Activity Y. If I open the Activity B from Activity Y, this Activity B is not always know how to open Activity A because the parent of B can be another B or A. B only know his parent. The problem is how to detect that Activity A is reachable automatically without creating a new instance from Activity B? This way, I can make my code like the following on Activity B.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (canGoUpToActivityA()) { // this means this Activity B is opened from Activity A directly (A -> B) or indirectly (A -> B -> ... -> B), not from Activity Y
NavUtils.navigateUpFromSameTask(this);
return true;
} else {
Intent intent;
if (TYPE_B.equals(mParent.getType())) {
intent = new Intent(this, ActivityB.class);
} else {
intent = new Intent(this, ActivityA.class);
}
intent.putExtra(EXTRA_ITEM, mParent)
startActivity(intent);
return true;
}
default:
return super.onOptionsItemSelected(item);
}
}
EDIT
If anybody down voting me because they think the solution is as simple as singleTop to Activity A, that's mean you guys don't understand my problem. See the last sentence of my first paragraph. I don't have any problem with going up from Activity B to Activity A, no matter how deep it is if Activity B is opened from Activity A.
Without the above onOptionsItemSelected, I can go up to Activity A from Activity B if Activity B is opened from Activity A directly (A -> B) or indirectly (A -> B -> ... -> B). This is not my problem.
The problem comes when I opened Activity B from Activity Y. I can't just go back to Activity A because Activity A rely on information from Activity X. If I open Activity B from Activity Y, then I go up, I should go to the parent of Activity B, where it can be A or another B.
The above code without canGoUpToActivityA() part will solve my problem. With that code, when I open Activity B from Activity Y, then going up should always go to the parent of B. That's already correct (B only know its parent, which can be not A).
But, when I open Activity B from Activity A, then I go up, it will launch the parent of Activity B. If I open Activity B from Activity A directly (A -> B), it's is indeed what I want. But, when I open Activity B from another Activity B (A-> B -> ... -> B), that's the problem. Because I should go up to Activity A, not the parent of Activity B which can be another Activity B.
I'm still not clear on what exactly you want, so I'll break this up into snippets:
If you want to launch a parent of Activity B and ensure that it isn't "launching itself", you can use the singleTop flag as noted by others to ensure that only one instance of B is ever on the top. You mentioned you don't have an issue with that, but you've listed that as an example, so just keep that in mind.
You've also mentioned that you check if the parent is A before launching Activity A. If all you want to do is actually launch the previous activity in the stack, there is no need for an Intent. Just finish your activity and it will exit the stack, showing the previous activity.
If you have a set activity that you should launch when going back, you can simply launch it with an intent. At this point, it doesn't matter what the previous activity is, because you are explicitly starting an activity for a given class. Again, you may look at the FLAG_ACTIVITY_REORDER_TO_FRONT flag to ensure that an existing activity is not recreated.
Lastly, if you have some complex logic that requires you to know the full stack history, you can always pass data through your bundle. A simple example is an arraylist of the simple class name so you know everything in the current task.
Edit: Since you've also added that you depend on information from previous classes, I take it that you need more than just the class name.
Note that you can always pass data through the bundles so that they are retained through all subsequent activities. You can also pass all the current data by calling putExtras.
And if your entire flow is geared towards going to a child and then passing data back to a parent, consider using [startActivityForResult](https://developer.android.com/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int)). That way, you can set result codes and data and finish your activity to directly pass information to the previous activity, without launching a new intent in a forward flow manner.

Back Button closes the Application in Android

I have an Application.Suppose there are three Activities A,B,C.
A->B(Sub-Activity)->C(Sub-Activity).
I have set up these kind code to switch to next activity.
setContentView(R.layout.B);
And Problem is When i click back button on emulator or phone while i am on Activity B or C,closes the application window come back to home.
I want that if i will press back button on Activity C it will firstly move to Activity B and then to A,Afterwards if i'll click again to back button then it comes to home-screen or closes application window.
Any methods or something wrong in my code or have to edit ?
You can override the default back press and tell it you reset your content view but you will have to keep track of the stack yourself.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//code to reset view
return true;
}
return super.onKeyDown(keyCode, event);
}
This said I really recommend you look at allow android to handle the stack in the default manner. Your method will end up causing you headaches in the future.
You need to actually start a new activity and then set the layout in there for the back button to work. Have a look at Tasks and Back Stack
Just setting the view to a new layout is not the same as starting a new activity. From your code, it appears you're just changing the layout and not starting a new activity.
As the method setContentView says, you are just changing the content view for the Activity A. Check The Activity lifecycle and the method startActivity to start new Activity, and read and the Tasks and Back Stack for more information.
As you're using setContentView , you're not switching between activities.
You actually are just changing the content of one and only one activity. Which explains the reason why when you press the back button it closes the application window.
activity A / content A -> activity A / content B -> activity A / content C
if you want to go from an activity to another: you should use Intent and startActivity.
for example you implement a button within the onClick function of the button you implement this:
Intent i = new Intent(this, ActivityTwo.class);
startActivity(i);
and in a different Java file named ActivityTwo.java you implement a class ActivityTwo which extends Activity, within the onCreate method you set a different view, which might be equivalent to content B
you're application scheme will be like this:
activity A / content A -> activity B / content B -> activity C / content C
When you'll be on activity C and you'll press the back button you'll go to activity B.

How to destroy an Activity so it doesn't show up when the back button is pressed?

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.

How to properly remove all activity stack?

Activity A -> Activity B -> Activity C -> Activity D. Pressing back in Activity D should navigate user out of the application, whereas Back should work normally for Activity C, B and A. i.e. C -> back -> B -> back A -> back -> exit.
I tried settings flags with Activity.FLAG_ACITIVITY_CLEAR_TOP, etc.. with different combination. Nothing seems to work. Minimum API level 7.
For #1 Pressing back in Activity D should navigate user out of the application
In ActivityD, you can override onBackPressed or onKeyDown method and then start ActivityA with flag FLAG_ACTIVITY_CLEAR_TOP with an Exit flag(via putExtra method). In ActivityA, you can get that Exit flag value and call finish() if Exit flag is set true.
In Activity A's onCreate method you will have to do is
if (getIntent().getBooleanExtra("EXIT", false)) {
finish();
}
In ActivityD's onBackPressed or onKeyPressed method,
intent = (this, ActivityA.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("EXIT", true);
startActivity(intent);
For #2 Exit from ActivityA
You can simply call finish() method on onBackPressed or onKeyPressed.
Have you tried overriding the functionality of the BACK button in Activity D? I'm quite sure this is very related to what you need: Override back button to act like home button
Understand the Android activity life cycle, too.
"Pressing back in Activity D should navigate user out of the application"
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
moveTaskToBack(true);
return true;
}
return super.onKeyDown(keyCode, event);
}
That's the normal behavior of OS, you don't have to do anything special for it.
Android activities are stored in the activity stack. Going back to a previous activity could mean two things.
You opened the new activity from another activity with startActivityForResult. In that case you can just call the finishActivity() function from your code and it'll take you back to the previous activity.
Keep track of the activity stack. Whenever you start a new activity with an intent you can specify an intent flag like FLAG_ACTIVITY_REORDER_TO_FRONT or FLAG_ACTIVITY_PREVIOUS_IS_TOP. You can use this to shuffle between the activities in your application. Haven't used them much though. Have a look at the flags here

Android resumes my Activity even if i call FINISH on BackButton

I have an activity A that launches B with an Intent. (B is a MapActivity and has some async code)
in B i have the following code
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
// Log.d(this.getClass().getName(), "back button pressed");
finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
This simply not work. I mean that when I press the back button on the phone, the current activity B disappears and the activity A that launched B is shown.
If I press again on A the button that launch B, I see B is exactly how it was when I closed it. SAME text in textboxes, same Map position... So i think the activity B is not really closed.
How can I close it for real so when I launch again it, activity B is cleas as new born?
EDIT: just to make the question clearer:
I want it to work like this: when the user is on activity B and BACK button is pressed, B has to be closed and destroyed. When the user again launches B from A, B has to be launched as a NEW activity, with blank field, reset map, etc., etc., ... just like the first time the user launches B from A.
Instead of returning true, try returning super.onKeyDown(keyCode, event) after finish().
You can try 1 more thing: specify android:noHistory="true" in the manifest for that activity.
Specifying this attribute doesn't keep the activity on the Activity Stack.
http://developer.android.com/guide/topics/manifest/activity-element.html#nohist
Have you tried lauching B by calling startActivityForResult() in A?
Do all your processing in B and then ensure you call finish on it and this should clear all data in it.
Please let me know if it works.
It's obvious. OnSaveState is called when finishing activity, and this activity is popped out of the stack. Best practice for you to clear the situation is to log all the lifecycle events in both activities, it will help to figure out where to put initializing your B activity.
Yes, and one more thing try researching onNewIntent method in B activity i suppose it will be really helpfull
As i stated in my last comment to the post, #Jianhong given me the correct answer (aslso if as a comment). As he don't copied the comment as answer in time, i add this answer and mark it as the ACCEPTED. Thanks #Jianhong!
Answer:
#Jianhong OMG! you completely right! i checked for this problem in past days but i couldn't find it as... i've not UPDATED from SVN. my coworker inserted lines of code that prefill fields by some static var!

Categories

Resources