How to avoid duplicate fragments? - android

I have a button in my fragment (fragment_x) with the below OnClickListener:
private void onClickAddButton(View view){
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment_y fragment_y = new Fragment_y();
fragmentTransaction.add(R.id.rl_activity_main_container, fragment_x);
fragmentTransaction.commit();
}
The problem is that this button is always visible, so clicking it again will add one more fragment_y and the screen gets messed up. How how do I check whether fragment_y has already been added, so that I can avoid creating a duplicate fragment_y?

You can ask the FragmentManager if the Fragment is already added:
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentByTag(tag);
if (fragment == null) {
// fragment must be added
fragment = new Fragment();
fm.beginTransaction().add(R.id.container, fragment, tag);
} else {
// fragment already added
});

Related

Common way to switch fragments without loosing state

I am pretty new to android development so I am curious how to work properly with Fragments.
My application contains a BottomNavigationActivity which switches between 3 fragments with this code:
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_montage_order_detail, fragment).commit();
I am storing the Fragments in a List<Fragment> to avoid loosing the current state. But everytime I replace the fragment with another the method onDestroy() is called.
I know, I know I could add and remove the fragment in the fragmentmanager instead of replacing it. I googled alot and most of the tutorials tell me to replace the fragment.
Whats the common way to keep a fragments state without recreating it on every call?
Find the solution
It will not recreate fragment anytime
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().add(R.id.content_montage_order_detail, fragment).commit();
Use fragment TAG at time of creation of fragment then when you want to get it again use findFragmentByTag. if fragment already created then old one will be find by fragment manager.
Fragment previousFragment = fragmentManager.findFragmentByTag("TAG");
I suggest you use show,not forreplace
protected void addFragmentStack(Fragment fragment) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (this.mContent != fragment) {
if (fragment.isAdded()) {
ft.hide(this.mContent).show(fragment);
} else {
ft.hide(this.mContent).add(getFragmentViewId(), fragment);
}
this.mContent = fragment;
}
ft.commit();
}
Try using switchFragment to switch fragment, it will show fragment if it is already added.
Use fragmentTransaction.show method to re-use existing fragment i.e. saved instance.
public void switchFragment (Fragment oldFragment, Fragment newFragment, int frameId) {
boolean addFragment = true;
FragmentManager fragmentManager = getFragmentManager ();
String tag = newFragment.getArguments ().getString (BaseFragment.TAG);
Fragment fragment = fragmentManager.findFragmentByTag (tag);
// Check if fragment is already added
if (fragment != null && fragment.isAdded ()) {
addFragment = false;
}
// Hide previous fragment
String oldFragmentTag = oldFragment.getArguments ().getString (BaseFragment.TAG);
if (!tag.equals (oldFragmentTag)) {
FragmentTransaction hideTransaction = fragmentManager.beginTransaction ();
Fragment fragment1 = fragmentManager.findFragmentByTag (oldFragmentTag);
hideTransaction.hide (fragment1);
hideTransaction.commit ();
}
// Add new fragment and show it
FragmentTransaction addTransaction = fragmentManager.beginTransaction ();
if (addFragment) {
addTransaction.add (frameId, newFragment, tag);
addTransaction.addToBackStack (tag);
}
else {
newFragment = fragmentManager.findFragmentByTag (tag);
}
addTransaction.show (newFragment);
addTransaction.commit ();
}
Ya, you can also manage the state by managing the backstack.

Redirect the fragment when click on button

I am using this code for replacing the fragment but there is a problem, it's not replacing the old fragment it just override on old fragment so please tell me what is the problem here.
public void selectFrag1(View rootView) {
Fragment frag;
if (rootView == findViewById(R.id.startup1)) {
frag = new S_SignupFragment();
} else {
frag = new F_SignupFragment();
}
FragmentManager fragManager = getSupportFragmentManager();
FragmentTransaction fragTransaction = fragManager.beginTransaction();
fragTransaction.replace(R.id.fragment_signup,frag);
fragTransaction.commit();
}
Are you sure that you pass the parent view, that is going to hold your fragment on the line fragTransaction.replace(R.id.fragment_signup,frag); ?
For fragmentTransaction.replace(...,...) you need to specify a container for your fragment and the fragment itself. Check where does your R.id.fragment_signup directs. More information you could find in this SO question: Unable to replace fragment on button click
fr = new FragmentOne();
fm = getSupportFragmentManager();
fragmentTransaction = fm.beginTransaction();
fragmentTransaction.add(R.id.fragment_place,fr);
fragmentTransaction.commit();
if you use same code then add this before call first button setonclicklistner

Resume/bring to top active (but hidden) fragment

I have added 3 fragments to my Activity with
String name = "fragment1"; // and ..2 and ..3
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.content_frame, fragment, name);
fragmentTransaction.addToBackStack(name);
fragmentTransaction.commit();
The last added (third) Fragment now is visible on top.
Now I want to resume to the first added Fragment. But how?
I can find this Fragment with
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment firstFragment = fragmentManager.findFragmentByTag("fragment1");
If I call fragmentManager.getFragments() I still can find all three Fragments.
How to bring firstFragment back to top, make it visible again?
You can hide your 2nd and 3rd fragment and make your 1st fragment visible. So you'll have the effect that first fragment is shown on top and others are invisible.
solution:
Use the FragmentTransaction's show and hide method. Firs you need to find all the fragment and call the FragmentTransaction to show and hide 2nd and 3rd fragments.
Here's how I do it in my app when I want to switch to fragment:
FragmentTransaction transaction = getFragmentManager().beginTransaction();
if (fragment.isAdded())
{
transaction.show(fragment);
}
else
{
transaction.replace(R.id.container, fragment);
}
transaction.addToBackStack(null);
transaction.commit();
Note the use of show.
It ended up with this:
/**
* #param tag name of the fragment to resume and to bring to top
* #return true if fragment has been found
*/
private boolean bringFragmentToTop(String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if (fragment != null) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
for (Fragment f : fragmentManager.getFragments()) {
if (f == fragment)
fragmentTransaction.show(f);
else
fragmentTransaction.hide(f);
}
fragmentTransaction.commit();
return true;
}
return false;
}

onstart() on Fragment is getting called twice in android

I have an activity on which I have one fragment. In onStart() of fragment I have all network calls.When app comes from background onStart() is getting called twice and all network are called twice and I also observed that onCreate()is called only once.Has some one faced such issue.Please help me out.
My code for fragment transaction is as below
MainFragment myFragment = new MainFragment ();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_frame, myFragment, "MyFragment");
fragmentTransaction.commitAllowingStateLoss();
Thanks in advance !!!
Try checking whether the fragment is already added before replacing
final FragmentManager fragmentManager = getSupportFragmentManager();
final Fragment content = fragmentManager.findFragmentById(R.id.content_frame);
if (content == null || !(content instanceof MainFragment)) {
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
final MainFragment myFragment = new MainFragment();
fragmentTransaction.replace(R.id.content_frame, myFragment, "MyFragment");
fragmentTransaction.commitAllowingStateLoss();
}
commit or commitAllowingStateLoss is an asynchronous excute, so fragmentManager.findFragmentById(R.id.content_frame); will a null before first commit finished, that will cause replace called twice.
you can debug onStart function, and see the hashCode of current Fragment object.
I replace commit to commitNow:
FragmentManager fragmentManager = activity.getFragmentManager();
Fragment lifeFragment = fragmentManager.findFragmentByTag(TAG_FRAGMENT);
if (lifeFragment == null || !(lifeFragment instanceof LifeFragment)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
fragmentManager.beginTransaction()
.add(new LifeFragment(), TAG_FRAGMENT)
.commitNowAllowingStateLoss();
}else {
fragmentManager.beginTransaction()
.add(new LifeFragment(), TAG_FRAGMENT)
.commitAllowingStateLoss();
}
}

Compare fragments

I've got the next code to switch between 4 fragments in a container [Main, A, B, C].
I need back button to go back to [Main] no matter how the user has navigated through fragments. For example, if I go [Main] >> [A] >> [C] when pressing back should go to [Main].
But I'm not getting the desired result. I think that I'm not doing well the coparisson between fragments.
Launcher MainFragment = new Launcher();
public void switchFragment(Fragment pFragment) {
FragmentManager fm = getSupportFragmentManager();
Fragment currentFragment = fm.findFragmentById(R.id.fragment_container);
if (pFragment == MainFragment){
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, pFragment).commit();
}
else if (currentFragment == MainFragment && pFragment != MainFragment){
//Fragment fr = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, pFragment).addToBackStack(null).commit();
}
else {
//Fragment fr = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, pFragment).commit();
}
currentFragment = pFragment;
}
UPDATE--
I've seen this way is working better, but still makes issue. If I navigate through some fragments without returning back to the Main fragment, when I press back it doesn't go back. It's like if there was some issue with the popbackstack().
public void switchFragment(Fragment pFragment) {
FragmentManager fm = getSupportFragmentManager();
Fragment currentFragment = fm.findFragmentById(R.id.fragment_container);
if (pFragment.equals(MainFragment)){
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, pFragment).commit();
}
else if (currentFragment.equals(MainFragment) && !pFragment.equals(MainFragment)){
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, pFragment).addToBackStack(null).commit();
}
else {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, pFragment).commit();
}
}
This functionality can be achieved by removing .addToBackStack from your fragment transactions.
Here is the Android reference for back stack functionality within fragments: http://developer.android.com/training/implementing-navigation/temporal.html#back-fragments
I finally get the dessired result just replacing the fragment I want on the back_key onClickListener:
final OnClickListener goBack = new OnClickListener() {
#Override
public void onClick(View v) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, MainFragment).commit();
}
};
This way, if In the future I need to go back to another fragment instead of the Main, I'll just add a condition to compare fragment tags and do something depending the tag.

Categories

Resources