Check if a fragment exists and reuse it - java

I'm using the following code to create a fragment everytime the user click on an item in a list view.
But in this way the fragment is created at every user click. What I want is to reuse the old fragment (if it exists) and only reload its content (don't create a new one).
MagazineViewFragment fragment = new MagazineViewFragment();
fragment.openStream(itemSelected);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit();
How can I do?

There're multiple ways, probably the most easy one is to check if the current Fragment in your container is an instance of FragmentXYZ (in your case MagazineViewFragment).
Example
Fragment mFragment = getFragmentManager().findFragmentById(R.id.container);
if (mFragment instanceof MagazineViewFragment)
return;

Add tag when you call your fragment from activity:
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentByTag( MagazineViewFragment.TAG);
if (fragment == null) {
MagazineViewFragment fragment = new MagazineViewFragment();
fragment.openStream(itemSelected);
getFragmentManager()
.beginTransaction()
.add(R.id.container, fragment, MagazineViewFragment.TAG)
.commit();
}
If you need only to update itemSelected - see broadcasts or listeners.

Something like this might help:
getFragmentManager().findFragmentById(fragmentId);
Do not forget the null check.

Related

Opening a fragment which replaces nav_host with being able to go back

I am trying to show a new fragment where the nav_host_fragment is but I want the old one to show whenever I click on backButton or on an X in my app (I added that already).
In the state that it is in right now it won't let me get out of the PlaylistFragment.
I also tried around with FragmentTransaction.add(...) but I couldn't figure how I get this working
My Code:
MainActivity.java:
Fragment fragment = new PlayListFragment(position);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment oldFragment = fragmentManager.findFragmentByTag(fragment.getClass().getName());
//if oldFragment already exits in fragmentManager use it
if (oldFragment != null) {
//fragment = oldFragment;
}
fragmentTransaction.replace(R.id.nav_host_fragment, fragment, fragment.getClass().getName());
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragmentTransaction.addToBackStack("playlist");
fragmentTransaction.commit();
PlaylistFragment.java:
getActivity().getSupportFragmentManager().popBackStack("playlist", 0);
EDIT:
When I tried putting null instead of "playlist" in the backstack:
Yup. Then I see both fragments overflowing each other:
Normal state:
https://prnt.sc/12yitg5
When clicking on the "downloaded songs":
https://prnt.sc/12yiu79
When clicking back in the fragment:
https://prnt.sc/12yiuy6
EDIT: When I click on the X again it shows me the home fragment while bottom nav highlights the Library tab.

Replace a Fragment with another from a separate java class

I have a Recycler View in a Fragment that I have an adapter class for in a separate file. I am trying to make it so that when you click on a RecyclerView Item it replaces the current fragment with a new one. The code to replace a fragment with another that I had been using previously is this:
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.nav_host_fragment, NewFragment.class, null);
transaction.addToBackStack("CurrentFragment");
transaction.commit();
And this works inside the fragment, but since I have to call it from the java class I tried this instead:
FragmentManager fragmentManager = ((AppCompatActivity) context).getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.nav_host_fragment, NewFragment.class, null);
transaction.addToBackStack("CurrentFragment");
transaction.commit();
And this just layers the new fragment on top of the current one. If I try making a class in the Current Fragment with the transaction code in it and call it, it doesn't work because of the static context.
Is there any way to do this?

What is the best way to add fragment in the Tabs android

My application had a bottom navigation bar which has 5 tabs.
So according to these tabs, I have 5 fragments
When I click on the tab, the fragment changed according to that tab.
I can switch fragment by using the method beginTransaction().replace...
I dont want the fragment to be destroyed and recreated again each time I switch tabs, so my solution is sth like this
//I init 5 fragments
Fragment1 frag1 = new Fragment1();
Fragment2 frag2 = new Fragment2();
Fragment3 frag3 = new Fragment3();
Fragment4 frag4 = new Fragment4();
Fragment5 frag5 = new Fragment5();
//When I click on tab, for example tab1, I hide all fragments except tab1
//hide all fragments
getSupportFragmentManager()
.beginTransaction()
.hide(fragment1) //Fragment2, 3, 4, 5 as well
.commit();
//show fragment 1
getSupportFragmentManager()
.beginTransaction()
.show(fragment1)
.commit();
It works very well, but the problem is sometimes 2 fragments show at once time (I dont know why because I hide all fragments)
Any other way to achieve that? Switch fragment without destroying it and creating it again.
for adding fragment I make this code for my project, hope it will be help.
public static void replaceFragment(Fragment fragment, FragmentManager fragmentManager) {
String backStateName = fragment.getClass().getName();
String fragmentTag = backStateName;
Fragment currentFrag = fragmentManager.findFragmentById(R.id.frame_container);
Log.e("Current Fragment", "" + currentFrag);
// boolean fragmentPopped = fragmentManager.popBackStackImmediate(backStateName, 0);
int countFrag = fragmentManager.getBackStackEntryCount();
Log.e("Count", "" + countFrag);
if (currentFrag != null && currentFrag.getClass().getName().equalsIgnoreCase(fragment.getClass().getName())) {
return;
}
FragmentTransaction ft = fragmentManager.beginTransaction();
// if (!fragmentPopped) {
ft.replace(R.id.frame_container, fragment);
ft.addToBackStack(backStateName);
ft.commit();
// }
currentFrag = fragmentManager.findFragmentById(R.id.frame_container);
Log.e("Current Fragment", "" + currentFrag);
}
hope this will be help you, and use this method in entire project for replacing fragment.
Using ViewPager with FragmentPagerAdapter suits for you in this case.
Then use ViewPager#setOffsetPageLimit(5). This will help you show/hide your fragments without recreating it again.
Follow this tutorial
Let try it, then tell me if your problem is solved or not. ;)
you don't have to need to hide the fragment just replace the fragment like this method:
public void setFragment(Fragment fragmentWhichYouWantToShow) {
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.container, fragmentWhichYouWantToShow);
ft.commit();
}
Try to make it in a singe transaction.
protected void showAsRootFragment(Fragment fragment, #NonNull String tag) {
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = supportFragmentManager.beginTransaction();
if (supportFragmentManager.getFragments() != null) {
for (Fragment attachedFragment : supportFragmentManager.getFragments()) {
if (attachedFragment != null && !tag.equals(attachedFragment.getTag())) {
transaction.hide(attachedFragment);
attachedFragment.setUserVisibleHint(false);
}
}
}
if (!fragment.isAdded()) {
transaction.add(R.id.frame_container, fragment, tag);
fragment.setUserVisibleHint(true);
} else {
transaction.show(fragment);
fragment.setUserVisibleHint(true);
}
transaction.commit();
}

on popBackStack() which method invoked in previous fragment

I have Fragment A.
On clicking some button, i add Fragment B above Fragment A.
FragmentB fragmentB= new FragmentB ();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.content_home, fragmentB, "fragmentB");
fragmentTransaction.hide(FragmentA.this);
fragmentTransaction.addToBackStack(FragmentA.class.getName());
fragmentTransaction.commit();
I perform some action in Fragment B. After finishing my work i popBackStack() current fragment.
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.popBackStack();
Now i Fragment A. Since i used "ADD fragment" all my values are kept in edittext.
I want to know, which method is invoked when i come back to Fragment A,
is it onResume()..?
I have to put log in onResume, seems like it not going to onResume!
instead of fragmentTransaction.add(R.id.content_home, fragmentB, "fragmentB");
use
fragmentTransaction.replace(R.id.content_home, fragmentB, "fragmentB");
refer link Difference between add(), replace(), and addToBackStack()
try below code
FragmentB fragmentB= new FragmentB ();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_home, fragmentB, "fragmentB");
fragmentTransaction.hide(FragmentA.this);
fragmentTransaction.addToBackStack(FragmentA.class.getName());
fragmentTransaction.commit();
According to Fragment documentation, your fragment will be resumed after pressing back.
https://developer.android.com/guide/components/fragments.html
if you do call addToBackStack() when removing a fragment,
then the fragment is stopped and will be resumed if the user navigates
back.
But you said,
I have to put log in onResume, seems like it not going to onResume!
Then you may have some problems in your code:
- If you do
fragmentTransaction.hide(FragmentA.this);
then you may need to use FragmentTransaction.show(Fragment), in order to display FragmentA again. And then it will go to onResume().

Fragment visible behind last fragment and goes on

Having Navigation drawer in Activity and changing Fragments by these lines of code
switch (menuItem.getItemId()) {
case R.id.home:
menuItem.setChecked(true);
drawerLayout.closeDrawer(GravityCompat.START);
if (getSupportFragmentManager().findFragmentByTag("ranking") == null) {
getSupportFragmentManager()
.beginTransaction()
.add(R.id.list_view_container, new HomeFragment(),
"ranking")
.addToBackStack("ranking")
.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
} else {
getSupportFragmentManager().popBackStack("ranking", 0);
}
return true;
case R.id.current_event:
menuItem.setChecked(true);
drawerLayout.closeDrawer(GravityCompat.START);
if (getSupportFragmentManager().findFragmentByTag("ranking1") == null) {
getSupportFragmentManager()
.beginTransaction()
.add(R.id.list_view_container, new CurrentEvents(),
"ranking1")
.addToBackStack("ranking1")
.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
} else {
getSupportFragmentManager().popBackStack("ranking1", 1);
}
return true;
}
I wanted Fragment to remain in memory so that it should not rebuilt again and again and fetch data from internet again and again so I have put the above method to get that but now, when I am changing the fragment by navigation drawer one fragment is replacing another and goes on and also I have to press back button=number of times new fragment created to exit from application. I want fragment in Backstack but not like this which is replacing one another. I want just one method at time. please help
Since you're using add(), the previous Fragment will not be removed from the container.
You should replace the calls to add() with replace(). For example, case R.id.home would become:
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.list_view_container, new HomeFragment(),
"ranking")
.addToBackStack("ranking")
.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit();
I wanted Fragment to remain in memory so that it should not rebuilt again and again and fetch data from internet again and again
You could try Fragment's setRetainInstance(true) to do that but it's not recommended (and I've never used it).
The other way which is more appropriate is to use Fragment's onSaveInstanceState(). You can read about it at Developer Android.
You can Check This Scenario, Hopefully it solve your Problem:-
Try to Attach and Detach the Fragment from FragmentTransaction. When
you Move to Next Fragment detach the last one Fragment From
FragmentTransaction and when you wants to use it again then attach it.
See sample code for how to Detach and Attach the Fragment, It will
help you :
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
AndroidFragment androidFragment = (AndroidFragment) fm.findFragmentByTag("android");
AppleFragment appleFragment = (AppleFragment) fm.findFragmentByTag("apple");
android.support.v4.app.FragmentTransaction ft = fm.beginTransaction();
/** Detaches the androidfragment if exists */
if(androidFragment!=null)
ft.detach(androidFragment);
/** Detaches the applefragment if exists */
if(appleFragment!=null)
ft.detach(appleFragment);
/** If current tab is android */
if(tabId.equalsIgnoreCase("android")){
if(androidFragment==null){
/** Create AndroidFragment and adding to fragmenttransaction */
ft.add(R.id.realtabcontent,new AndroidFragment(), "android");
}else{
/** Bring to the front, if already exists in the fragmenttransaction */
ft.attach(androidFragment);
}
}else{ /** If current tab is apple */
if(appleFragment==null){
/** Create AppleFragment and adding to fragmenttransaction */
ft.add(R.id.realtabcontent,new AppleFragment(), "apple");
}else{
/** Bring to the front, if already exists in the fragmenttransaction */
ft.attach(appleFragment);
}
}
ft.commit();
`For Reference see this onTabChanged :` [http://wptrafficanalyzer.in/blog/creating-navigation-tabs-using-tabhost-and-fragments-in-android/][1]

Categories