5

J'ai une activité avec les onglets de navigation en bas qui changent les fragments en elle. Lorsque je clique sur ces onglets, à un moment donné, cela cesse de fonctionner. Le code s'exécute très bien car je mets quelques logs dedans. Mais les fragments ne sont pas commutés.FragmentTransaction cacher/montrer ne fonctionne pas parfois

code

est en Kotlin mais il est plutôt droit devant

fun showTabFragment(tag: String) { 
     val currentFragment: Fragment? = supportFragmentManager.fragments?.lastOrNull() 
     var fragment = supportFragmentManager.findFragmentByTag(tag) 
     val fragmentExists = fragment != null 
     if (fragment == null) { 
      when (tag) { 
       TAG_LOGBOOK -> fragment = LogbookFragment() 
       TAG_RECIPES -> fragment = RecipesFragment() 
       TAG_PROFILE -> fragment = ProfileFragment() 
       else -> fragment = MeetingPlacesFragment() 
      } 
     } 

     val transaction = supportFragmentManager.beginTransaction() 

     if (currentFragment != null) { 
      Log.i("jacek", "hiding " + currentFragment.javaClass.simpleName) 
      transaction.hide(currentFragment) 
     } 

     if (fragmentExists) { 
      Log.i("jacek", "showing " + fragment.javaClass.simpleName) 
      transaction.show(fragment) 
     } else { 
      Log.i("jacek", "adding " + fragment.javaClass.simpleName) 
      transaction.add(R.id.container, fragment, tag) 
     } 

     transaction.commit() 
    } 

Les fragments sont assez lourds. Je vais essayer avec quelques légers, mais cela ne devrait pas poser de problème à mon avis. Y a-t-il autre chose que je pourrais essayer?

J'utilise la dernière bibliothèque de soutien - 25.2.0 Aussi je ne suis pas intéressé à remplacer les fragments comme point est d'ajouter une animation sans les recréer Crossfade

+0

Peut-être il y a un problème lorsque vous appelez 'hide()' et ensuite 'show()' sur les mêmes fragments dans la même transaction? Comme quand 'currentFragment' fait référence aux mêmes fragments que' fragment', ce qui peut certainement arriver ici. En parlant de cela, je pense qu'il est faux de prétendre que le dernier fragment de la liste 'supportFragmentManager.fragments' sera le dernier fragment affiché (plutôt le dernier ajouté). Vous devriez soit parcourir tous les 'fragments' et en chercher un qui a' isVisible() 'comme vrai ou simplement stocker la dernière balise fragmentée montrée et la trouver plus tard. –

Répondre

1

Le problème est ici même si vous » En cachant le fragment "courant", il y a d'autres fragments chargés dans la mémoire et cela donne un comportement incohérent.

Vous devriez être capable de résoudre ce problème en masquant tout le fragment sauf le fragment que vous voulez montrer.

Grâce à cette réponse. Show hide fragment in android

par exemple:

private FragmentA fragmentA; 
private FragmentB fragmentB; 
private FragmentC fragmentC; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    fragmentA = FragmentA.newInstance(); 
    fragmentB = FragmentB.newInstance(); 
    fragmentC = FragmentC.newInstance(); 

} 

protected void displayFragmentA() { 

    FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
    if (fragmentA.isAdded()) { 
     ft.show(fragmentA); 
    } else { 
     ft.add(R.id.fragement_container, fragmentA); 
    } 

    if (fragmentB.isAdded()) { ft.hide(fragmentB); } 

    if (fragmentC.isAdded()) { ft.hide(fragmentC); } 

    ft.commit(); 
} 

De même, vous devrez écrire des fonctions pour displayFragmentB() et displayFragmentC()

1

@ La réponse d'Ali est bonne, mais imaginez si vous avez 5 fragments. Ceci est une autre façon de montrer/cacher vos fragments:

// in BaseFragment 
    public abstract String getTAG(); 

    //in FragmentA, FragmentB and FragmentC 
    public String getTAG(){ 
     return TAG; 
    } 

    //Activity containing the fragments 
    //android.support.v4.app.Fragment;  
    private FragmentA fragmentA; //inherited BaseFragment 
    private FragmentB fragmentB; //inherited BaseFragment 
    private FragmentC fragmentC; //inherited BaseFragment 
    private ConcurrentHashMap<String,BaseFragment> mapOfAddedFragments = new ConcurrentHashMap<>(); 


    /** 
    * Displays fragment A 
    */ 
    private void displayFragmentA() { 
     displayFragment(fragmentA) 
    } 

    /** 
    * Displays fragment B 
    */ 
    private void displayFragmentB() { 
     displayFragment(fragmentB) 
    } 

    /** 
    * Displays fragment C 
    */ 
    private void displayFragmentC() { 
     displayFragment(fragmentC) 
    } 


    /** 
    * Loads a fragment using show a fragment 
    * @param fragment 
    */ 
    private void displayFragment(BaseFragment fragment){ 
     if(!mapOfAddedFragments.containsKey(fragment.getTAG())) 
      mapOfAddedFragments.put(fragment.getTAG(), fragment); 

     showFragment(fragment.getTAG(), R.id.containerBody); 
    } 

    /** 
    * Displays a fragment and hides all the other ones 
    * @param fragmentTag is the tag of the fragment we want to display 
    */ 
    private void showFragment(String fragmentTag, @IdRes int containerViewId){ 
     FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction(); 
     BaseFragment fragment = null; 

     fragment = mapOfAddedFragments.get(fragmentTag); 
     if(fragment != null) { 
      if (fragment.isAdded()) 
       ft.show(fragment); 
      else { //fragment needs to be added to the frame container 
       ft.add(containerViewId, fragment, fragment.getTAG()); 
      } 
     } 
     else //the chosen fragment doesn't exist 
      return; 

     //we hide the other fragments 
     for (ConcurrentHashMap.Entry<String, BaseFragment> entry : mapOfAddedFragments.entrySet()){ 
      if(!entry.getKey().equals(fragmentTag)){ 
       BaseFragment fragmentTemp = entry.getValue(); 
       // Hide the other fragments 
       if(fragmentTemp != null) 
        if(fragmentTemp.isAdded()) 
         ft.hide(fragmentTemp); 
      } 
     } 

     //commit changes 
     ft.commit(); 
    } 

Et les instancier vous pouvez le faire dans la méthode onCreate() de votre activité:

//don't forget to get the .TAG elsewhere before using them here 
    //never call them directly 
    private void instantiateFragments(Bundle inState) { 
     if (inState != null) { 
      fragmentA = inState.containsKey(FragmentA.TAG) ? 
        (FragmentA) getSupportFragmentManager().getFragment(inState, FragmentA.TAG): 
        FragmentA.newInstance(FragmentA.TAG,"0"); 

      fragmentB = inState.containsKey(FragmentB.TAG) ? 
        (FragmentB) getSupportFragmentManager().getFragment(inState, FragmentB.TAG): 
        FragmentB.newInstance(FragmentB.TAG,"1");   

      fragmentc = inState.containsKey(FragmentC.TAG) ? 
        (FragmentC) getSupportFragmentManager().getFragment(inState, FragmentC.TAG): 
        FragmentC.newInstance(FragmentC.TAG,"2");   
     } 
     else{ 
      fragmentA = FragmentA.newInstance(FragmentA.TAG,"0"); 
      fragmentB = FragmentB.newInstance(FragmentB.TAG,"1"); 
      fragmentc = FragmentC.newInstance(FragmentC.TAG,"2"); 
     } 
    }