getChildFragmentManager() on programmatically (dynamically) added Fragments?
Asked Answered
P

2

29

How to use (or "Can we use") getChildFragmentManager() on programmatically (dynamically) added Fragments?

Here is my example.

I have one MainActivity, one OuterFrag, and one InnerFrag. I will add the OuterFrag to MainActivity dynamically by the FragmentManager. And also, I will add the InnerFrag to the OuterFrag also dynamically by the FragmentManager. But I want to add InnerFrag exactly as a child of the OuterFrag, not replacing OuterFrag and be the new child of the MainActivity.

I want to keep this hierarchy: MainActivity -> OuterFrag -> InnerFrag. So MainActivity can always call OuterFrag.

But NOT change from this hierarchy: MainActivity -> OuterFrag to this hierarchy: MainActivity -> InnerFrag that MainActivity will loss the OuterFrag.

Here is my example code.

MainActivity.java

package com.example.frag;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity {

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

        getSupportFragmentManager().beginTransaction().add(R.id.frameLayout, new OuterFrag()).commit();
        getSupportFragmentManager().executePendingTransactions();

        System.out.println("Before: "
                + getSupportFragmentManager().findFragmentById(R.id.frameLayout));

        ((OuterFrag) getSupportFragmentManager().findFragmentById(R.id.frameLayout))
                .addInnerFrag();

        System.out.println("After: "
                + getSupportFragmentManager().findFragmentById(R.id.frameLayout));
    }
}

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/frameLayout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
</FrameLayout>

OuterFrag.java

package com.example.frag;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class OuterFrag extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.outer_frag, container, false);
    }

    public void addInnerFrag() {

        getFragmentManager().beginTransaction().replace(this.getId(), new InnerFrag()).commit();
        getFragmentManager().executePendingTransactions();

//        getChildFragmentManager().beginTransaction().add(this.getId(), new InnerFrag()).commit();
//        getChildFragmentManager().executePendingTransactions();
    }
}

outer_frag.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="i am the OUTER frag" />

InnerFrag.java

package com.example.frag;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class InnerFrag extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.inner_frag, container, false);
    }
}

inner_frag.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="i am the INNER frag" />

Currently, the above code can run without errors. But it is actually changing InnerFrag as the new child of MainActivity. This can be verified by the two System Print Out statements that the Before: Object and the After: Object is changed. In the OuterFrag.java, if the getChildFragmentManager() statements are run instead of the getFragmentManager() statements, we will get the following runtime error:

12-07 02:29:38.406: E/AndroidRuntime(12051): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.frag/com.example.frag.MainActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f070000 (com.example.frag:id/frameLayout) for fragment InnerFrag{46e32748 #0 id=0x7f070000}

Using getChildFragmentManager() is theoretically correct. It can be used in a non-programmatically added fragment (which means changing activity_main.xml's <FrameLayout> to <fragment>, add attribute android:name="com.example.frag.OuterFrag", and remove the first getSupportFragmentManager() statement in MainActivity.java). And it is keeping the correct hierarchy: MainActivity -> OuterFrag -> InnerFrag. But the words of original fragment (outer_frag.xml) can never be taken away.

In conclusion, I want to reference OuterFrag in MainActivity always. And I want OuterFrag act as a placeholder to load different InnerFrags. In short, I want to call getChildFragmentManager() in OuterFrag, when it is added programmatically (dynamically).

Plausive answered 7/12, 2012 at 6:11 Comment(1)
Did you get this working? My question is when do you add the InnerFrag so it fits seamlessly with the OuterFrag's lifecycle?Handbag
B
45

In conclusion, I want to reference OuterFrag in MainActivity always. And I want OuterFrag act as a placeholder to load different InnerFrags. In short, I want to call getChildFragmentManager() in OuterFrag, when it is added programmatically (dynamically).

If you want this then make your OuterFrag have a container layout as its content and add whatever InnerFrag to that container. The layout file for the OuterFrag will be:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
/>

Of course you could have other views in the layout for the OuterFrag if you want that. Then your addInnerFrag method will be:

public void addInnerFrag() {
        getChildFragmentManager().beginTransaction().add(R.id.fragContainer, new InnerFrag()).commit();
        getChildFragmentManager().executePendingTransactions();
}

The code for adding the OuterFrag to the main activity remains valid.

Bubo answered 7/12, 2012 at 6:29 Comment(11)
Hi @Luksprog i have followed the above method and the Inner Fragment is added to OuterFragment. But the OuterFragment is not replacing the content. It is added as a view and the previous content in the OuterFragment is also visible. I have also tried using beginTransaction().replace but there is no change in the op. Please help me ...................Pannikin
@Pannikin Please post a new question providing more details about your problem. Keep in mind that a fragment transaction will not replace the views that are already in the layout where the fragment will be added. If you want to replace that as well then put those initial views in another fragment.Bubo
@Luksprog hello, how can add InnerDetailFrag to InnerFrag?Fortyfour
@Luksprog how i manage backpress from innerFrag to make visible outerFrag?Cramfull
@HirenDabhi The outer fragments is always visible as it holds the inner fragments. If you want to remove the inner fragment get a reference to the outer fragment's FragmentManager and use one of its pop... methods.Bubo
@Luksprog i mean backpress of device and pass data from outerFrag to innterFrag, it is possible with UI button but how can i handle device back press.Cramfull
@HirenDabhi It's not clear what you're asking. You talk about handling the back press(what I said above still stands) but also sending data from the other fragment to inner fragment(which should be dismissed on back pressed?). You should post a new question providing more details about what you're trying to do.Bubo
@Luksprog using below code in inner fragment's some button press event will show outer fragment, but how could i achieve the same thing using device's back press. getParentFragment().getChildFragmentManager().popBackStack();Cramfull
@HirenDabhi Override the onBackPressed() callback of the activity and get references to the outer fragment and do what you do above: getSupportFragmentManager().findFragmentByTag("the tag of the outer fragment").getChildFragmentManager().popBackstack();.Bubo
Once parent fragment loads childfragment parent fragment menuitems will be removed?Oleg
Yes it's is removed if child fragment calls MenuItems.clear() !!Oleg
S
-1

If you want to call addInnerFrag() within your OuterFrag.java code, you can do it like this:

OuterFrag.java:

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    addInnerFrag();
}
Stygian answered 9/6, 2016 at 13:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.