Android - Clearing Navigation Backstack - java

I have 4 pages.
From page_1 > page_2 > page_3 > page_4.
Once the user reaches page_3 and clicks a button, it navigates to page_4. Once the button is clicked, I want to clear all the navigation history so when the user goes back on page_4, the app quits rather than going back to page_3.
I've tried:
Intent intent = new Intent(this, page_4.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
But nothing happens. I can still go back to page_3, page_2 etc. How do I make it so that when the user clicks on the button on page_3, he goes to page_4 and from page_4 there shouldn't be any navigation history?

I'm not sure that these methods will works for you. The first method is by adding FLAG_ACTIVITY_TASK_ON_HOME when you go to page_4 from page_3:
Intent intent = new Intent(this, page_4.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
startActivity(intent);
So once you press BACK button within page_4, it directs you to HOME activity (MainActivity) first, then you can press BACK button again to exit the app from this activity.
From the docs:
If set in an Intent passed to Context.startActivity(), this flag will cause a newly launching task to be placed on top of the current home activity task (if there is one). That is, pressing back from the task will always return the user to home even if that was not the last activity they saw. This can only be used in conjunction with FLAG_ACTIVITY_NEW_TASK.
The second way is, set android:noHistory="true" within the activity in manifest. Apply this attribute for page_1 till page_4. But this method has two disadvantages. First, your activity is completely has no back stack. The second, the activities you set with this attribute get destroyed once you press HOME button or when you get an incoming call. I never found this topic, so please CMIIW.

for all the other activities like page_3,page_2,page_1,
Use FLAG_ACTIVITY_NO_HISTORY(If set, the new activity is not kept in the history stack.) :
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

Try set Intent.FLAG_ACTIVITY_NO_HISTORY And Intent.FLAG_ACTIVITY_TASK_ON_HOME
From documentation
Intent.FLAG_ACTIVITY_NO_HISTORY
If set, the new activity is not kept in the history stack. As soon as
the user navigates away from it, the activity is finished. This may
also be set with the noHistory attribute.
Intent.FLAG_ACTIVITY_TASK_ON_HOME
If set in an Intent passed to
Context.startActivity(), this flag will cause a newly launching task
to be placed on top of the current home activity task (if there is
one). That is, pressing back from the task will always return the user
to home even if that was not the last activity they saw. This can only
be used in conjunction with FLAG_ACTIVITY_NEW_TASK.

Related

How to prevent activity from reloading itself when coming back after visiting other activities?

I have 5 different activities in my app, i enable the user to navigate between those activities by clicking buttons. The main activity has a RecyclerView in it (used to make a feed). the other activities are used for search, profile, notifications, etc. The user opens the app, the main activity is displayed. The user can scroll through the feed (which is the RecyclerView) in the main activity, now the user decides to go to other activities, search, profile, etc. Now, when the user clicks on the button that navigates to the main activity, I want to open back the main activity and display the recycler view at the same scrolling position and with the same items as was when the user just left it off.
Note: I'm not talking here about pressing the back button or using any goBack functions. I want to enable the user to use the main activity and visit all other activities and after all of that he will be able to come back to the main activity and find the feed exactly as he left it off.
In every activity I have five navigation buttons that allowing the user to go from every activity to every activity: click on profileBtn will open the profile activity, etc.
There is a way in which i can back up the state of the recycler view in the main activity before the user wants to go to other activities and restore it when the user clicks on the homeBtn?
Code:
HomeActivity.java:
public void profileBtn_OnClick(android.view.View view)
{
Intent intent = new Intent(getBaseContext(), ProfileActivity.class);
startActivity(intent);
}
ProfileActivity.java, SerachActivity.java, NotificationsActivity.java:
public void homeBtn_OnClick(android.view.View view)
{
/* HERE I WANT TO OPEN BACK THE HOME ACTIVITY AND DISPLAY THE FEED
EXACTLY AS IT WAS WHEN THE USER LEFT IT, HOW DO I DO THAT? */
Intent intent = new Intent(getBaseContext(), HomeActivity.class);
startActivity(intent);
}
You can use the launchMode="singleTask".
The system creates the activity at the root of a new task and routes
the intent to it. However, if an instance of the activity already
exists, the system routes the intent to the existing instance through
a call to its onNewIntent() method, rather than creating a new one.
You can get more information about launchMode here: https://developer.android.com/guide/topics/manifest/activity-element
android:launchMode=["standard" | "singleTop" | "singleTask" | "singleInstance"]
<activity
android:name=".ui.HomeActivity"
android:launchMode="singleTask" />
Please do NOT use the special launch mode singleTask for this purpose. It causes more problems than it solves. These launch modes have complex side-effects that are not obvious and will cause you more problems later.
Your problem is simple to solve using standard Android behaviour. Change your method to look like this:
public void homeBtn_OnClick(android.view.View view)
{
Intent intent = new Intent(getBaseContext(), HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
The flag CLEAR_TOP tells Android to remove all activities from the task that are on top of the target Activity (in this case the target Activity is HomeActivity.
The flag SINGLE_TOP tells Android not to recreate HomeActivity, but to reuse the existing instance of it.

Bring activity front if it is running or create new one with backpress

Let me explain detailed; I have notification and this notification opens B activity with two cases.
Cases :
If app is closed. (not running on background)
If app is opened. (on background or front)
Case-1
I click to the notification and it opens the B activity with case-1. When i press back i want to go to the A activity and kill B activity. I dont need B activity anymore. Everything easy from here without using flags. When I'm on B activity and press back two times from here, it goes A activity and then closes the app. My trouble here is, if i open the app from navigation buttons of phone (can't remember the name of this button) app is opening from B activity. That's not what i expected. I want to open A activity. Don't want to see B activity anymore.
Case-2
I click to the notification and it opens the B activity with case-2.When i press back i want to bring A activity to the front, without creating anything new. If i press back on B activity, two times and close the app and then again re-open app from navigation button of phone, want to open app from A activity.
So how can i make this correctly, i tried to use flags (i already read docs) but couldn't get work.
What flags should i use when i open the B activity and onBackPress method of B activity to go A activity as i wanted
This should be achievable by adding
android:launchMode="singleTask"
to the A activity in the Manifest, then you can just open A activity from B activity onBackPressed and you will have A only once in the stack.
If it's not working the way you want, you can create an abstract class that extends Activity and handle the stack in a static object, then A & B must extend this new class
try this
Intent intent = new Intent(context, YourActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
try this
android:launchMode="singleTask" in android manifest file
You can achive this by adding FLAG_ACTIVITY_REORDER_TO_FRONT
Intent i = new Intent(context, Activity.class);
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(i);
You May try this isTaskRoot() Which will return B is root
if it is true then launch A
other wise you may finish B
B Activity
#Override
public void onBackPressed() {
if (isTaskRoot()) {
//call A which is not exist
Intent i =new Intent(B.this,A.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}else {
//Finish B if A Already Exixt
finish();
}
}
You can call B Activity on Notification Click
if A is present then u can finish B else you can launch A
If set FLAG_ACTIVITY_CLEAR_TOP, 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 put this in ActivityB onBackPressed:
Intent i = new Intent(ActivityB.this , ActivityA.calss);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
finish();
How solve case 1:
finish(); on ActivityB BackPressed method make ActivityB finish after open ActivityA. So after opens ActivtyA, ActivityB will shut down.
How solve case 2:
With this combination flag, It will do what you want. It will close all activities in stack and just keep destination activity. If instance of activity exist it will use it and calls OnNewInstance and if not it will creates new one.
If this is the only instance of Activity B being used, you can add the flag noHistory to the manifest for Activity B
android:noHistory="true"
This will stop Activity B being added to the back stack, this is also possible dynamically by using the Intent Flag FLAG_ACTIVITY_NO_HISTORY when calling Activity B.
As for having Activity A start when Activity B is killed #Quentin Menini's answer of having a single task activity set in the manifest will work if that is the only way you wish Activity A to be accessed, or the Intent Flag Intent.FLAG_ACTIVITY_REORDER_TO_FRONT as #Naimish Vinchhi has suggested, will have the desired effect in this instance.
https://developer.android.com/reference/android/content/Intent.html
link to see all possible Intent flags
https://developer.android.com/guide/topics/manifest/activity-element.html
link for all possible manifest activity options

Remove all activities except the first one

I want to program Home button, so it will remove all Activities in stack, except one. I did it like in here: How to finish every activity on the stack except the first in Android
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
Intent intent = new Intent(this, AMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
break;
...
but this way doesn't suit me, because it removes ALL Activities (including the first one) and starts the first one again. For example - if I check user password in onCreate(), he would be asked again.
How to remove all Activities from stack, but so the first one will not be "touched" ?
add following property to your AMainActivity's Activity tag in your manifest.xml.
android:launchMode="singleTop"
Yes, according to the documentation of Intent.FLAG_ACTIVITY_CLEAR_TOP:
The currently running instance of activity B in the above example will either receive the new intent you are starting here in its onNewIntent() method, or be itself finished and restarted with the new intent. If it has declared its launch mode to be "multiple" (the default) and you have not set FLAG_ACTIVITY_SINGLE_TOP in the same intent, then it will be finished and re-created; for all other launch modes or if FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be delivered to the current instance's onNewIntent().
So, use additional Intent flag:
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
And your activity should not be recreated. Instead, it will just get the new intent delivered via a call to onNewIntent().
You can use ExcludeFromRecent = "true" flag in Activities declaration in manifest, which you don’t want to be in Stack.

How can i call a specific tab activity from another regular activity in android by using intent

I have 3 tabs (act1,act2,act3) and i have activities without tabs(A,B), if the user open activity A and press button OK then alarm will start and after 10 seconds it will go to act2
this all done, but i tried many thing :
1- when i go to act2 it does not display the tabs. just act2 activity
so i change the code and tried to :
2- when i go to activity tabs it show me the first tab(act1) but i wanna act2
how can i do it
i wanna display act2 with tab
Give me any reference or hint.
Thanks in Advance.
Try this: Send an intent (via startActivity() as usual) to bring the activity to the front which contains the tabs. Send an extra parameter with the activity containing the TAG or some identifier for tab, you want to be opened. Evaluate the extra parameter in the activity, which contains the tab and let it switch to the tab as indicated by the parameter.
EDIT
To start the tab activity with a parameter:
final Intent i = new Intent(this, YourTabActivity.class);
i.putExtra(TAB_TAG, tag); // TAB_ID see comment below, define some tags for the tabs
this.startActivity(i);
To extract the parameter from the intent:
Overwrite onNewIntent() in the tab activity and introduce a field lastIntent, set this.lastIntent = this.getIntent() there. (Otherwise you will always access the intent which started the activity in the first place, not the most recently sent intent!)
in onResume process the last intent:
final Bundle extras = this.lastIntent.getExtras();
final String tabTag = extras.getString(TAB_TAG); // define the key TAB_TAG as static string
Now use tabTag to set the current tab.

How to make my activity transparent?

I am making a keyboard ( InputMethodService ), which needs to launch a dialog.
As I found out, a service can not launch a dialog. So I made a separate activity which is called from the service by
Intent dialogIntent = new Intent(getBaseContext(), dialog.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(dialogIntent);
and show a dialog. The problem is that this activity replaces the previous one, where the user was typing something.
What do you think would be the best way to make it "transparent" ( i.e. not to push away the previous activity ) and also what would be the best way for this activity to talk back to the service, saying that dialog option was picked.
Thanks! :)
If this is an Activity (not a Dialog), you can add a dialog theme in the activity section of your AndroidManifest:
android:theme="#android:style/Theme.Dialog"
As for getting back what the user pressed, you should use startActivityForResult(...)
You should NOT launch an activity from an IME. This is a huge break in the IME flow -- the activity comes along and does an app switch from the current app, taking focus from it, and breaking your connection with its current editor.
Also there is no way to get a result back from it, because you can only use startActivityForResult() from an activity.
To show a Dialog in your IME, just use Dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG before showing the dialog.
To resume in code what have been said, let me share some code for those who need to test the solution:
// 1. CREATE THE DIALOG
val builder: AlertDialog.Builder = AlertDialog.Builder(this, R.style.Theme_AppCompat_Light)
builder.setTitle("Title").setMessage("This is the message for the user. ")
val mDialog = builder.create()
// 2. SET THE IME WINDOW TOKEN ATTRIBUTE WITH THE TOKEN OF THE KEYBOARD VIEW
mDialog.window?.attributes?.token = this.mKeyboardView.windowToken
// 3. SET THE TYPE OF THE DIALOG TO TYPE_APPLICATION_ATTACHED_DIALOG
mDialog.window?.setType(WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG)
// 4. SHOW THE DIALOG
mDialog.show()

Categories

Resources