I have Navigation drawer and a series of fragments. On last fragment of hierarchy, i've got UP button on action bar. As this button clicked, onOptionsItemSelected(MenuItem item) of root activity is called, where i can find out, which button is clicked in the following predicate :
else if ( item.getItemId() == android.R.id.home )
{
System.out.println("android.R.id.home\n\n");
// super.onBackPressed();
// getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).commit();
return true;
}
How can i remove current fragment? I've read about back stack, but that approach requires saving fragments in stack using keys. How can i avoid this procedure?
I had this problem before of fragments on top of each other when I first started using them. I use this code to add fragments:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction =fragmentManager.beginTransaction();
Fragment fragment = new CustomFragment(); // your fragment to add
transaction.replace(R.id.content_frame, fragment,CustomFragment.TAG); // a string in case you need to check with fragment is currently visible.
transaction.addToBackStack(null);
transaction.commit();
This will ensure that when you press back button the current one will disappear and the one before it will show.
hope it works with you.
You can actually just pop off the back stack, no tracking via keys/tags needed: FragmentManager.popBackStack(). Just use null when adding your fragments to the back stack, the system will automatically select a tag for it.
Related
When working with java in Android Studio, how do I get back from a fragment to a previous fragment?
To use the bottom tab, I am using fragments divided into three in MainActivity. I opened another fragment on that fragment to input information, but when I press Back on the phone, the application quits. How should I do it?
This is the code I added to MainActivity.
**public void onBackPressed() {
List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
for(Fragment fragment : fragmentList){
if(fragment instanceof onBackPressedListener){
((onBackPressedListener)fragment).onBackPressed();
return;
}
}
if(System.currentTimeMillis() - lastTimeBackPressed < 1500){
finish();
return;
}
lastTimeBackPressed = System.currentTimeMillis();
Toast.makeText(this,"Press the 'Back' button again to finish.",Toast.LENGTH_SHORT).show();
}**
And can the page that receives information from being entered in a different way than a fragment?
Is it possible to delete the fragment while storing the input information after it is input from the fragment? When I go back, the stack is still piled up, so I keep seeing the previously entered information.
For the fragment you add that allows the user to input information, make sure to call:
fragmentTransaction.addToBackStack(null);
during the fragment transaction where you add the fragment.
Then get rid of the onBackPressed override, it's not necessary.
addToBackStack() will enable automatic handling of the BACK button press, removing the fragment transaction.
There is a NavigatorView in which I am using the NavController. The whole problem is that when replacing the Fragmenta, I immediately set fragmentTransaction.addToBackStack (String.valueOf (FragmentRink3)); and when navigating to another NavController when clicking on OnBackPressed, is applied to the fragment from the previous NavController where the replacement was made. It's hard to explain. Is it possible to somehow do so that each of the lower navigation menu has its own, I don’t know, a list of clicks, according to which the sequence of transitions to fragments was determined? I know I explained very poorly, I will attach a gif to show the problem clearly.
As you can see, by clicking on the button, the fragment was replaced, then I went to the next menu and clicked OnBackPressed, and at this moment the fragment, which was replaced in the previous menu, went back. How to fix it?
I will replace the fragment as follows:
btn_close.setOnClickListener(v ->
{
FragmentRink4 fragment = new FragmentRink4(); // you fragment
FragmentManager fragmentManager = ((FragmentActivity) v.getContext()).getSupportFragmentManager(); // instantiate your view context
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.nav_controller_rink1, fragment);// your container and your fragment
fragmentTransaction.addToBackStack(String.valueOf(FragmentRink3));
fragmentTransaction.commit();
});
Here is a link to the project.
I'm fairly new to android studio, any help would be appreciated.
I have set up a bottom navigation bar programatically in my MainActivity - what's the best way to set this up with other fragments. I have three fragments, one for each tab in the navigation bar and other fragments which can be opened when buttons are pressed from the navigation bar fragments.
Where do I set up these other fragments? in the same activity that connects the fragments that are connected to the navigation bar or in a different activity.
How do I save the current state of the displayed fragment so that when I move to a different tab and then move back it will be in the same state as when I left it?
My question is, where do i set up these other fragments? in the same activity that connects the fragments that are connected to the navigation bar or in a different activity.
It's really up to you and how you want to display the fragments. You can display them in the same activity or open another activity. However bear in mind that if you open another activity, you will lose the navigation bar of the previous activity (an activity always uses the whole screen)
What does FragmentManager and FragmentTransaction exactly do?
How do I save the current state of the displayed fragment so that when
I move to a different tab and then move back it will be in the same
state as when i left it?
Read about the fragment lifecycle at https://developer.android.com/guide/components/fragments.html#Lifecycle
Specifically, you want to save your state in onSaveInstanceState, and the stuff you save will be sent back to you when the fragment is recreated in onCreate
I'd like to expand on what #rupps said, because I feel like the part about what do FragmentManager/Transaction do is not approached from where you are expecting.
I assume you're using a BottomNavigationView.
Regardless of the (important) lifecycle of Fragments, you have to understand that a Fragment is always attached to an activity (note: this is not true, but let's not talk about headless fragments for now).
The approach you can take is that the Activity layout looks like this: (in pseudo code)
<RelativeLayout width=match_parent height=match_parent>
<FrameLayout
id="#+id/your_fragment_container"
width=match_parent
height=match_parent
layout_above="#+id/navbar" />
<BottomNavigationView
id="#id/navbar"
width=match_parent
height=wrap_content
align_parent_bottom=true />
</RelativeLayout>
This way the BottomNavBar will always be present at the bottom of your layouts.
Now you have to deal with putting the fragments there… Let's say that you need to attach a Listener to that bar, and when you receive a callback that a new menu item has been selected… you can proceed to change the fragment (you will always get one event upon startup or you can force it during onCreate I suppose).
You will literally add a switch/if statement to the onNavigationItemSelected(MenuItem item) method.
and call addFragment(TAG); depending which case it is.
Pseudo-Code for you to get the idea:
private void addFragment(final String tag) {
final Fragment existing = getSupportFragmentManager().findFragmentByTag(tag);
if (existing == null) {
final Fragment newInstance = getNewFragmentInstanceWithTag(tag);
getSupportFragmentManager()
.beginTransaction()
.replace(getFragmentContainerLayout(), newInstance, tag)
.commit();
}
}
You'll also need to provide:
private int getFragmentContainerLayout() {
return R.id.your_fragment_container;
}
and…
public static final String TAB1_TAG = "TAB1_TAG";
public static final String TAB2_TAG = "TAB2_TAG";
public static final String TAB3_TAG = "TAB3_TAG";
protected Fragment getNewFragmentInstanceWithTag(String tag) {
switch (tag) {
case TAB1_TAG:
return Tab1Fragment.newInstance();
case TAB2_TAG:
return Tab2Fragment.newInstance();
case TAB3_TAG:
return Tab3Fragment.newInstance();
default:
return null;
}
}
So what the frog is the FragmentManager/Transaction?
Think of the Manager as a singleton object (one per app) that keeps a reference to your Fragments and can retrieve them for you (if they existed before). It handles Transactions (add/remove/hide/show, etc.) so you can later roll back them (say you add a fragment in a transaction, if you also addToBackStack() then you can simply tell the Manager: pop the last transaction, effectively rolling it back.
It's a monster. It had bugs for over 9000 years and it's not very intuitive; but once you get used to it, you just "use it".
In the main activity of my app there is a container that hosts fragments.
When a user clicks a button in the "default" fragment (the first fragment that is displayed), the fragment changes, and so do the actionbar buttons.
One of the buttons in the actionbar of this new fragment open another activity.
In that activity, when a user clicks the back button, the activity closes, and the fragment that was shown in the MainActivity (the fragment that opened the new activity) is still there (which is fine).
However, if a user clicks the back button again, it does not return to the previous fragment. While it does return when the activity does not open.
It turns out that opening the activity clears the backstack (verified by Logging the count from the FragmentManager class), while I'm not quite sure whether this is supposed to behave like this or not, it kinda makes sense. Unfortunately, it is not the behavior I desire.
MainActivity: Fragment A (default) ---> Fragment B ---> Acivity B
Therefore, my question is how can I keep the backstack after the activity resumes, if at all?
I tried searching for similar questions, but all questions I found actually asked how to clear the backstack.
Try that:
#Override
public void onBackPressed() {
Intent intent = new Intent(A_Acticity.this, B_Activity.class);
startActivity(intent);
}
Hope it helped! :)
Reading the documentation, there is a way to pop the back stack based on either the transaction name or the id provided by commit. Using the name may be easier since it shouldn't require keeping track of a number that may change and reinforces the "unique back stack entry" logic.
Since you want only one back stack entry per Fragment, make the back state name the Fragment's class name (via getClass().getName()). Then when replacing a Fragment, use the popBackStackImmediate() method. If it returns true, it means there is an instance of the Fragment in the back stack. If not, actually execute the Fragment replacement logic.
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
I have an Activity that displays 2 fragments. One acts as a list of options and includes a few textviews and the other is the corresponding fragment. What is the best way use OnClick for those text views to swap between the corresponding fragments?
Thank you in advanced, I really appreciate it.
this is the basic code for swapping fragments:
import android.support.v4.app.Fragment;
//If not using "support" fragment, use getFragmentManager()
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
//you can omit this, Android.R. has some built in anmations.
ft.setCustomAnimations(android.R.anim.slide_in_left, R.animator.fade_out);
//"replace" empties the container of all existing fragments.
ft.replace(container, myFrag, str_SomeID);
ft.commit();
Alternatively you can hide a fragment in place.
The basic code for hiding a fragment:
FragmentManager manager = getSupportFragmentManager();
fragment = manager.findFragmentByTag(str_SomeID);
if (fragment != null && !fragment.isHidden()){
manager.beginTransaction().hide(fragment).commit();
}