findFragmentByTag() returns null after perform a FragmentTransaction using replace() method

44,276

Solution 1

I've fixed it! I called getSupportFragmentManager().executePendingTransactions() after doing the transaction and it worked! After calling that method I can get the fragment using both findFragmentById() and findFragmentByTag() methods.

Solution 2

if you use setRetainInstance(true) than you can't use findFragmentByTag() in onCreate from the Activity. Do it at onResume

see the documentation: setRetainInstance

Solution 3

I'll start by apologising since I'm still very new myself...

I think the problem may be in the declaration of the fragmentTag static String not properly getting access from the class's instances, just change that line to:

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

Also, I would be more explicit when declaring instances, for example:

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

I hope you get this sorted, as I seen this question posted earlier and was surprised that it hadn't got any activity yet.

Also, here are a couple of links to the android documentation on replace:

Android Training - Replace

Android Reference - Replace

Solution 4

I had the same problem and realized that there is a really simple way to fix this. When using a tag please do make sure to add the

fragmentTransaction.addToBackStack(null); 

method so that your Fragment is resumed instead of destroyed as mentioned in the developer guides.

If you don't call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and is later resumed if the user navigates back.

You can find this at the end of this section.

Every time I tried to reference back to my created Fragment, it turns out it had already been destroyed so I lost about 30 minutes trying to figure out why my Fragment was not being found through a simple findFragmentByTag(); call.

Hope this helps!

Share:
44,276
Guillermo Barreiro
Author by

Guillermo Barreiro

Telecommunications Engineer, technology enthusiast since I was a children, self-taught, always willing to learn new things and develop projects to make people’s life easier. Sports, music, and traveling lover.

Updated on June 13, 2020

Comments

  • Guillermo Barreiro
    Guillermo Barreiro almost 4 years

    My Android app consists three fragments: A, B and C. They're loaded in the two containers defined in the MainActivity layout.

    When the app is started, it shows the fragmentA loaded in the left_container and the fragmentC in the right_container.

    If you press the button in the fragmentA, a FragmentTransaction changes FragmentC by FragmentB.

    At the moment everything OK. But the trouble appears when I try to get a reference to the loaded fragmentB using findFragmentByTag(), because it returns null. I've used the method replace in the FragmentTransaction and I've finished it with commit(), but there isn't way to call FragmentB method. My 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>
    

    Please help me! I'm a beginner in Android development!

  • Guillermo Barreiro
    Guillermo Barreiro over 10 years
    It didn't work. The method findFragmentByTag() still returns null despite the changes that you've said me.
  • Kenny164
    Kenny164 over 10 years
    Try replacing the FRAGMENT_TAG with just normal string values then, e.g ft.replace(R.id.right_container, new FragmentB(), "fragmentB");
  • Guillermo Barreiro
    Guillermo Barreiro over 10 years
    Neither works. I cant' find an error in my code, and I've tried lots of changes, but I'm still getting a null fragment in the method findFragmentByTag()
  • Guillaume
    Guillaume almost 10 years
    I'd rather override onAttachFragment and act when the fragment is ready.
  • IgorGanapolsky
    IgorGanapolsky over 9 years
    I don't see how this solves the problem, or where to put executePendingTransactions().
  • IgorGanapolsky
    IgorGanapolsky over 9 years
    @Kenny164 FRAGMENT_TAG is a String constant anyway. What is the point of replacing it??
  • Guillermo Barreiro
    Guillermo Barreiro over 9 years
    @igor-ganapolsky You have to put executePendingTransactions()after calling the .commit() method of the FragmentTransaction. This forces the system to execute the transaction if it hadn't been done yet.
  • Sami Eltamawy
    Sami Eltamawy almost 9 years
    It didn't work for me. Add it after the commit() and still have a null value fragment
  • ToolmakerSteve
    ToolmakerSteve over 8 years
    If not using v4-compatibility support library, I think you should do getFragmentManager().executePendingTransactions() rather than getSupportFragmentManager().executePendingTransactions().
  • Jonas
    Jonas over 7 years
    Doesn't work for me. Getting "FragmentManager is already executing transactions" exception in some cases when calling executePendingTransactions() and some other fragments get messed up.
  • Hephaestus
    Hephaestus about 7 years
    No joy. Still getting null even with getFragmentManager().executePendingTransactions(); placed after the .commit() call.
  • Shn
    Shn almost 6 years
    For those who added executePendingTransactions() and didn't have success, just try adding the Fragment object to your class and reference that in your method that executes the fragment transaction. It's not perfect, but it's a workaround. Make sure you update the Fragment object each time you replace/add a fragment to avoid the object being null...
  • Georgiy Chebotarev
    Georgiy Chebotarev over 4 years
    I didn't understand why this answer is correct)) It doesn;t help for findFragmentByTag. Where is your full answer and real result?