web-dev-qa-db-fra.com

findFragmentByTag () renvoie null après avoir effectué une FragmentTransaction à l'aide de la méthode replace ()

Mon application Android se compose de trois fragments: A, B et C . Ils sont chargés dans les deux conteneurs définis dans la disposition MainActivity

Lorsque l’application est lancée, elle montre le fragmentA chargé dans le left_container et le fragmentC dans le right_container

Si vous appuyez sur le bouton dans le fragmentA , une FragmentTransaction change FragmentC by FragmentB

Pour le moment tout va bien. Mais le problème apparaît lorsque j'essaie d'obtenir une référence au fragmentB chargé à l'aide de findFragmentByTag(), car il renvoie null. J'ai utilisé la méthode replace dans FragmentTransaction et je l'ai terminée avec commit(), mais il n'y a pas moyen d'appeler FragmentB method. Mon code:

MainActivity.Java:

 public class MainActivity extends Activity{
 static String fragmentTag = "FRAGMENTB_TAG";

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


    //Adds the left container's fragment
    getFragmentManager().beginTransaction().add(R.id.left_container, new FragmentA()).commit(); //Adds the fragment A to the left container

    //Adds the right container's fragment
    getFragmentManager().beginTransaction().add(R.id.right_container, new FragmentC()).commit(); //Adds the Fragment C to the right container
 }

 /**
 * Called when the button "Activate Fragment B" is pressed
 */
public void buttonListener(View v){

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.right_container, new FragmentB(),fragmentTag); //Replaces the Fragment C previously in the right_container with a new Fragment B
        ft.commit(); //Finishes the transaction


        //!!HERE THE APP CRASHES (Java.lang.NullPointerException = findFragmentByTag returns null
        ((FragmentB) getFragmentManager().findFragmentByTag(fragmentTag)).testView();


    }
}

FragmentB.Java:

public class FragmentB extends Fragment {

public View onCreateView(LayoutInflater inflater,
        ViewGroup container,
        Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_b, container,false);

}


/**
 * Gets a reference to the text_fragment_b TextView and calls its method setText(), changing "It doesn't work" text by "It works!"
 */
public void testView(){
    TextView tv = (TextView)getView().findViewById(R.id.text_fragment_b);
    tv.setText("It works!");
}

}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="horizontal" >

<FrameLayout Android:id="@+id/left_container" Android:layout_width="0px" Android:layout_weight="50" Android:layout_height="match_parent"/>    
<FrameLayout Android:id="@+id/right_container" Android:layout_width="0px" Android:layout_weight="50" Android:layout_height="match_parent"/>

</LinearLayout>

fragment_b.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical" 
Android:layout_margin="5sp">

<TextView 
    Android:id="@+id/text_fragment_b"
    Android:text="It doesn't works!"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"/>

</LinearLayout>

Aidez-moi, s'il vous plaît! Je suis débutant en développement Android! 

30
Guillermo Barreiro

Je l'ai réparé! J'ai appelé getSupportFragmentManager().executePendingTransactions() après avoir effectué la transaction et cela a fonctionné! Après avoir appelé cette méthode, je peux obtenir le fragment en utilisant à la fois les méthodes findFragmentById() et findFragmentByTag()

62
Guillermo Barreiro

si vous utilisez setRetainInstance(true), vous ne pouvez pas utiliser findFragmentByTag() dans onCreate à partir de l'activité. Faites-le à onResume

voir la documentation: setRetainInstance

3
oli

Je vais commencer par m'excuser car je suis encore très jeune moi-même ...

Je pense que le problème vient peut-être de la déclaration de la chaîne statique fragmentTag dont l'accès n'est pas correctement accessible à partir des instances de la classe. Modifiez simplement cette ligne en:

private final static String FRAGMENT_TAG = "FRAGMENTB_TAG"; // using uppercase since it's a constant

De plus, je serais plus explicite lors de la déclaration d'instances, par exemple:

public void buttonListener(View v){

    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(R.id.right_container, new FragmentB(), FRAGMENT_TAG);
    ft.commit();

    FragmentB fragB = (FragmentB) getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
    fragB.testView();
}

J'espère que vous avez réglé ce problème, car j'ai déjà vu cette question et que je suis surpris de constater qu'il n'y a pas encore eu d'activité.

En outre, voici quelques liens vers la documentation Android sur replace:

Formation Android - Remplacer

Référence Android - Remplacer

1
Kenny164

J'ai eu le même problème et j'ai réalisé qu'il existe un moyen très simple de résoudre ce problème. Lorsque vous utilisez un tag, assurez-vous d’ajouter le 

fragmentTransaction.addToBackStack(null); 

méthode afin que votre fragment soit repris au lieu de détruit comme indiqué dans les guides du développeur. 

Si vous n'appelez pas addToBackStack () lorsque vous effectuez une transaction qui supprime un fragment, ce fragment est détruit lorsque la transaction est validée et que l'utilisateur ne peut pas y revenir. Par contre, si vous appelez addToBackStack () lors de la suppression d'un fragment, celui-ci est arrêté et repris ultérieurement si l'utilisateur revient en arrière.

Vous pouvez le trouver à la fin de cette section .

Chaque fois que j'essayais de faire référence à mon fragment créé, il s'avérait qu'il avait déjà été détruit. J'ai donc perdu environ 30 minutes à essayer de comprendre pourquoi mon fragment n'a pas été retrouvé par un simple appel findFragmentByTag();.

J'espère que cela t'aides!

1
Panos Gr

Nous constatons également ce problème, mais la cause est légèrement différente. La solution suggérée par https://stackoverflow.com/a/21170693/1035008 ne fonctionne pas pour nous. 

void updateFragment(Fragment newFragment) {
    FragmentTransaction ft = getFragmentManager().beginTransaction();

    // We have these 2 lines extra
    Fragment current = getChildFragmentManager().findFragmentByTag(fragmentTag);           
    if (current != null) { ft.remove(current); }

    ft.replace(R.id.right_container, newFragment, fragmentTag); //Replaces the Fragment C previously in the right_container with a new Fragment B
    ft.commit(); //Finishes the transaction

    //!!HERE THE APP CRASHES (Java.lang.NullPointerException = findFragmentByTag returns null
    ((FragmentB) getFragmentManager().findFragmentByTag(fragmentTag)).testView();
}

Et après avoir lu la documentation sur le remplacement: 

Remplacer un fragment existant qui a été ajouté à un conteneur. Cela revient essentiellement à appeler remove (Fragment) pour tous les fragments actuellement ajoutés qui ont été ajoutés avec le même conteneurViewId, puis add (int, Fragment, String) avec les mêmes arguments donnés ici.

Je me rends compte que l'appel remove n'était pas nécessaire car il est fait automatiquement par replace. Donc, après delete ft.remove(current), cela fonctionne bien. 

0
Yuchen Zhong

Assurez-vous que vous ajoutez ou remplacez le fragment de la manière appropriée

L'instruction suivante ajoutera le fragment mais renverra la valeur null lors de l'utilisation de getFragmentManager ().

transaction.add(R.id.mainContent, fragment);


De cette façon, ça va marcher; 

transaction.add(R.id.mainContent, fragment, tag);
0
lm2a