Fragments can be added/replaced/removed dynamically in the code. I have been using this method for my projects.
However I wonder what would be the difference (mainly in performance) if instead of creating a new fragment and adding it or replacing the current one, we just grab a handle to the current one and modify it.
For example, consider this simple scenario where the only purpose of a fragment is to display an image, and we want to modify that image:
Option 1) Create a new instance of my Fragment class and replace the fragment which is currently displayed:
MyFragmentClass fr = new MyFragmentClass();
fr.setImage(1);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.frame_layout_id, f)
...
Option 2) Just grab a reference to the currently displayed fragment and modify it:
MyFragmentClass fr = (MyFragmentClass)
fragmentManager.findFragmentById(R.id.frame_layout_id);
fr.setImage(1);
Is the whole process of creating a new fragment instance and adding it more efficient than calling findFragmentById?
Go through following information may be you get clarification
1- fragmentTransaction.addToBackStack(str);
Add this transaction to the back stack. This means that the transaction will be remembered after it is committed, and will reverse its operation when later popped off the stack.
2- fragmentTransaction.replace(int containerViewId, Fragment fragment, String tag)
It replace an existing fragment that was added to a container.
This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.
3- fragmentTransaction.add(int containerViewId, Fragment fragment, String tag)
Add a fragment to the activity state. This fragment may optionally also have its view (if Fragment.onCreateView returns non-null) into a container view of the activity.
What does it mean to replace an already existing fragment, and adding a fragment to the activity state and adding an activity to the back stack ?
There is a stack in which all the activities in the running state are kept. Fragments belong to the activity. So you can add them to embed them in a activity.
When you navigate to the current layout, you have the id of that container to replace it with the fragment you want.
You can also go back to the previous fragment in the backStack with the popBackStack() method. For that you need to add that fragment in the stack using addToBackStack() and then commit() to reflect. This is in reverse order with the current on top.
findFragmentByTag does this search for tag added by the add/replace method or the addToBackStack method ?
If depends upon how you added the tag. It then just finds a fragment by its tag that you defined before either when inflated from XML or as supplied when added in a transaction.
Related
I am using multiple fragments.
I am adding fragment over fragment as below
supportfragmentmanager
.beginTransaction()
.add(R.id.container_login, newFragment, newFragment.javaClass.simpleName)
.addToBackStack(newFragment.javaClass.simpleName)
.commitAllowingStateLoss()
Now the issue is, despite of adding new fragment, previous fragment is not losing focus.
Typing in edittext of current fragment types in previous fragment edditext.
Even action next also loses focus in current fragment and moves cursor in previous fragment.
Kindly help.
The fragment does not lose focus because you use .add method which adds the new fragment over the one which already exists in the container.
Use .replace() method which replaces the existing fragment from the container. This is similar to calling remove(Fragment) and then use .add() method.
If you want to add a fragment in one container is impossible but if you want to replace the fragment with another fragment is possible to do it, because one layout is for 1 fragment, not more than one, so you just need to replace the previous fragment with another fragment
I have a simple code if you want to replace the previous fragment with the new fragment
First, you need to add one method with the parameter of the fragment
fun openFragment(fragment: Fragment?) {
val transaction: FragmentTransaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.container_content, fragment!!)
transaction.commit()
}
If you want to replace the fragment with another fragment just call the method like this openFragment(FragmentClass.newinstance()) soo the previous fragment will be replaced with the new fragment
I hope this code can help you to solve your problem
During fragment transaction we normally uses add(int containerViewId, Fragment fragment) which simple adds fragment to containerview whose id we specified.But recently I came across add(Fragment fragment, String tag).Where will this fragment be added in fragment stack and UI?
From Android official
Calls add(int, Fragment, String) with a 0 containerViewId.
That means add (Fragment fragment, String tag) method calls add (int containerViewId, Fragment fragment,String tag) with containerViewId value 0.
From Pooyas's answer:
"0" is not a valid resource ID. So actually your fragment is created without any view.
It is possible to have fragments without the view so this method actually is used for those types of fragments which just created to do some processing but have no interactions with layouts
Fragment represents the behavior or a part of the user interface in one Activity. You can combine multiple fragments into a single activity to compile a multi-panel UI and reuse a fragment into multiple activities. A fragment is like a modular section of an activity, which has its own life cycle, receives its own input events and can be added or removed with the activity being executed (a kind of "subactivity" that can be reused in different activities).
Each fragment independently, such as adding or removing them. When
performing such a transaction with fragments, you can also add them to
a return stack that is managed by the activity - each return stack
entry in the activity is a record of the fragment transaction that
occurred.
so its added fragment stack.More details refer Fragments
How to replace Fragment_1 Fragment_2 with the ability to return back to the state and Fragment_1 (scroll, inputs, forms, other)?
enter image description here
If you use Activities, then you can use the method startActivityForResult. The work of this method perfectly shows the current task with fragments.
I do not want to save the values and then substitute them. We need that to Fragment_1 remained intact.
How to save the status of previous fragments at the opening of the new fragment_N and when you turn the screen using backstack?
Is there a ready library for the implementation of these tasks?
Instead of replacing fragment, You can add a new fragment and hide current one.
Something like this
FragmentTransaction t = getFragmentManager.beginTransaction();
t.hide(your_current_fragment);
t.add(container, new_fragment);
t.addToBackStack(TAG);
t.commit();
It will not loss the state of hidden fragment
FragmentTransaction t = getFragmentManager.beginTransaction();
t.hide(your_current_fragment);
t.add(container, new_fragment);
t.addToBackStack(TAG);
t.setCustomAnimations(R.anim.open_enter,R.anim.close_exit,R.anim.open_enter,R.anim.close_exit)
or
t.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
t.setTrans
t.commit();
replace FragmentPagerAdapter with a HorizontalScrollView contains 2FrameLayout for fragment.You can freely change fragment in FrameLayout.
So I've found a few similar cases, but nothing about this specific case.
I have a FrameLayout which I gave the id "container", and contains a few different fragments.
In my code for the activity that contains that FrameLayout, I'm trying to switch between the fragments with a function that receives a fragment.
In that code:
a. I have defined private FragmentManager fm = getSupportFragmentManager();
b. I have defined FragmentTransaction ft; to use later.
c. My function is:
private void setActiveFragment(Fragment fragment){
//Determine which button should be marked as "active"
determineButtonByFragment(fragment);
//Repalce fragment
ft = fm.beginTransaction();
ft.replace(R.id.container, fragment);
ft.addToBackStack(String.valueOf(fragment.getId()));
ft.commit();
}
Any idea why i would get this error on the "replace"?
EDIT:
Ok, I just realized a bit more about fragments. Since all 5 fragments are added to the FrameLayout, the "replace" won't work. You get the "can't chance container ID error" when you're trying to move a fragment from 1 parent view to another (Or in this, case, to the same one), without detaching it first.
Let's say I have fragments A, B, C, D, E.
If I want to replace to fragment B right now, I won't be able to do it until I remove it from it's original parent (Or at least that's how I think it works. please enlighten me otherwise). The only question that remains now, is how do I switch between my fragments correctly...
Alright, apparently you cannot use the "replace" method on fragments which are hard-coded in the layout:
Replacing a fragment with another fragment inside activity group
What I have to do now, is inside the function, to find a way to determine the fragment I want to display, create a new instance of it, and use "replace" on it.
I'm implementing menu navigation using Fragments. So I begin with Home, and then users can navigate to diferent sections and details of each section.
When a user changes section, then I call pop on the fragmentmanager backstack until I reach Home, and then load the new section.
This is all working as expected. But I'm getting this problem:
load a section that calls setHasOptionsMenu(true) on onResume()
loads another section (old section it's suposed to get out of the stack). I see it OK. No menu is shown
leave the application (for example, go to Android Laucher activity) and then when I return, I see the correct section, but it's showing the Menu of the old Fragment.
I've iterated the backstack and printed each fragment, and there it's not the fragment with the menu.
I put a debug mark on the onResume() method (where the setHasOptionsMenu(true) is flagged) and it indeed enters here, so the Fragment it's still somewhere.
I want to know if I'm doing something wrong and how could I solve it, thx
Update:
I'm using this code to load new fragments
fm.beginTransaction()
.add(container, sectionFragment.getFragment())
.addToBackStack(sectionFragment.getFragmentName())
.commit();
And for remove:
private void clearStack(){
int count = fm.getBackStackEntryCount();
while(count > 1){
fm.popBackStack();
count--;
}
}
NOTE 1: I'm using add instead replace because I don't want to loose the state of my fragment when I navigate back from detail section. When I load another different section, then I call clearStack to pop the stack up to 1, and then loads new fragment. At the end, I'm calling executePendingTransactions() to finish to remove the fragments from the transaction.
NOTE 2: I'm seeing that it is entering on my fragment onDestroy() method, so it is suposed to be destroyed. But I don't know why it is getting called again when the Main activity resumes.
I found that the problem was not in the logic of adding and removing fragment of the stack.
The problem was that some of the fragment loaded another fragments inside of it (it had ViewPager component). Then I thought that when the fragment was removed then these fragments were removed too.
This is true ONLY if you use getChildFragmentManager() method. This method MUST be used when loading fragments inside other fragmets. If not, then the fragments are asociated with the fragments activity.
popBackStack will just revert your last FragmentTransaction.
If you use FragmentTransaction.add, popBackStack will just call FragmentTransacetion.remove.
But if you call FragmentTransaction.replace, popBackStack will call FragmentTransaction.remove and FragmentTransaction.add
For your "NOTE 1" :
FragmentTransaction.replace will not change your fragment state.
I found this question, because after calling
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
this code fragmentManager.getFragments().size() returns me the maximum number of fragments, which were in the stack. I checked every fragment on null. And I found that some fragment is null in my case. Maybe it will help someone)
If you are really looking to remove fragments at once then follow:
How to replace Fragments of different types?
Otherwise use replace transaction for fragments to smooth transitiona and hassel free approach, see https://stackoverflow.com/a/23013075/3176433
Also understand Fragment lifecycle,
http://developer.android.com/guide/components/fragments.html
I had a similar problem where the popBackStack() didn't remove my fragment.
However, I noticed that I called the wrong FragmentManager, where I had to call getSupportFragmentMananger() instead of getFragmentManager().
Maybe there is a <fragment> or <androidx.fragment.app.FragmentContainerView> in an activity with android:name="androidx.navigation.fragment.NavHostFragment", app:defaultNavHost="true" and app:navGraph="#navigation/nav_graph".
In this case navigation is held by nav_graph. If you don't want to use NavController and NavHostFragment, maybe you should remove navigation and clean <fragment> tag.