onstart() on Fragment is getting called twice in android - 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();
}
}

Related

Attach/detach vs replace fragment

In the following piece of code, what's the point of using detach/attach fragments instead of just replacing them?
private void showFragment(String tag) {
String oldTag = mSelectedTag;
mSelectedTag = tag;
final FragmentManager fm = getSupportFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
final Fragment oldFragment = fm.findFragmentByTag(oldTag);
final Fragment fragment = fm.findFragmentByTag(tag);
if (oldFragment != null && !tag.equals(oldTag)) {
ft.detach(oldFragment);
}
if (fragment == null) {
ft.replace(R.id.container, getContentFragment(tag), tag);
} else {
if (fragment.isDetached()) {
ft.attach(fragment);
}
}
ft.commit();
}
Why can't I just write something like this?
private void showFragment(String tag) {
final FragmentManager fm = getSupportFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container, getContentFragment(tag), tag);
ft.addToBackStack(null);
ft.commit();
}
getContentFragment method, just in case:
private Fragment getContentFragment(String tag) {
Fragment fragment = null;
if (Frag1.TAG.equals(tag)) {
fragment = new Frag1();
} else if (Frag2.TAG.equals(tag)) {
fragment = new Frag2();
}
return fragment;
}
Here's the documentation for FragmentTransaction.detach() (emphasis added):
Detach the given fragment from the UI. This is the same state as when it is put on the back stack: the fragment is removed from the UI, however its state is still being actively managed by the fragment manager. When going into this state its view hierarchy is destroyed.
So a detached fragment is still "alive" inside the FragmentManager; its view has been destroyed but all of its logical state is preserved. So when you call attach(), you are getting the same fragment back.
FragmentTransaction.replace(), passing a new fragment, however, will cause you to wind up using two different instances of the same fragment class, rather than re-using a single instance.
Personally, I've never had a need to use detach() and attach(), and have always used replace(). But that doesn't mean that there isn't a place and time where they're going to be useful.

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.

Android find current fragment

I have 4 java class that i use as fragments: `F1,F2,F3,F4.
When i want to swich from one to other, i use this code:
android.app.FragmentManager FM = getFragmentManager();
FragmentTransaction FT = FM.beginTransaction();
F1 FP = new F1();
FT.add(R.id.where, FP,"F1");
FT.commit();
FM.executePendingTransactions();
If i want to make possible to return from one of them to the previous, i add addToBackStack(TAG) as following:
android.app.FragmentManager FM = getFragmentManager();
FragmentTransaction FT = FM.beginTransaction();
F1 FP = new F1();
FT.add(R.id.where, FP,"F1");
FT.addToBackStack("F1");
FT.commit();
FM.executePendingTransactions();
I have only one activity that chages the current fragment displayed.
I would get from it, the current fragment displayed.
I tried to write this, but now is always null.
Fragment now=getSupportFragmentManager().findFragmentByTag("F1");
if(now!=null && now.isVisible()) {
//some code for the current fragment
}
Try This it may be help to you
Fragment currentFragment = getFragmentManager().findFragmentById(R.id.where);
if (currentFragment instanceof F1) {
//do your stuff here
}

How to avoid duplicate fragments?

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
});

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