3

I'm currently having trouble with nesting fragments , I've created a SlidingTabLayout with two tabs , each tab with it's corresponding Fragment , In one tab I've added 5 child fragments to the parent fragment returned by the FragmentPagerAdapter, but I'm having trouble with the communication between the parent fragment and it's fragment children ,

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

            FragmentTransaction childManager=getChildFragmentManager().beginTransaction();
            childManager.add(R.id.linear08,new YearFragment08(),"year08");
            childManager.commit();
            YearFragment08 year08=(YearFragment08)getChildFragmentManager().findFragmentByTag("year08");
            year08.setinfo("This is fantastic");


}

`

public class YearFragment08 extends Fragment {
TextView yearInfo;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View v=inflater.inflate(R.layout.year_frag08,container,false);
    yearInfo=(TextView)v.findViewById(R.id.txt_yearInfo_08);
    return v;
}
 public void setinfo(String data){
    yearInfo.setText(data);
}

And THIS is the result .

02-09 21:45:48.078    2177-2177/com.compassasu.compass E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.compassasu.compass, PID: 2177
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.compassasu.compass.Fragments.YearFragment08.setinfo(java.lang.String)' on a null object reference
        at com.compassasu.compass.Fragments.HistoryFragment.onActivityCreated(HistoryFragment.java:33)
        at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1970)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1051)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1207)
        at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
        at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1572)
        at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:545)
        at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
        at android.support.v4.view.ViewPager.populate(ViewPager.java:1106)
        at android.support.v4.view.ViewPager.populate(ViewPager.java:952)
        at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1474)
        at android.view.View.measure(View.java:18788)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
        at android.view.View.measure(View.java:18788)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at android.support.v7.internal.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:124)
        at android.view.View.measure(View.java:18788)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
        at android.view.View.measure(View.java:18788)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at android.view.View.measure(View.java:18788)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
        at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
        at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
        at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
        at android.view.View.measure(View.java:18788)
        at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
        at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
        at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
        at android.view.View.measure(View.java:18788)
        at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2100)
        at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1216)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1452)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
        at android.view.Choreographer.doCallbacks(Choreographer.java:670)
        at android.view.Choreographer.doFrame(Choreographer.java:606)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5417)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

All I want to know is how does a child fragment receive data from the parent fragment .

Sherif Amr
  • 43
  • 5

1 Answers1

1

The problem is that you are trying to find the fragment by its tag before it has actually been added. Note the documentation for FragmentTransaction.commit():

Schedules a commit of this transaction. The commit does not happen immediately; it will be scheduled as work on the main thread to be done the next time that thread is ready.

As you can see the fragment is not added immediately so that is why null is returned when you try to get the Fragment.

To fix this you can use FragmentManager.executePendingTransactions() after committing the transaction to add the fragment immediately:

getChildFragmentManager().beginTransaction()
        .add(R.id.linear08,new YearFragment08(),"year08")
        .commit();

getChildFragmentManager().executePendingTransactions();
YearFragment08 year08=(YearFragment08)getChildFragmentManager().findFragmentByTag("year08");
year08.setinfo("This is fantastic");

Also note that a better way to do this would be to create the YearFragment08 fragment first and use Fragment arguments to pass the info you want to show in the Fragment. Then you would not need to use the above workaround since you will not need to call yearInfo.setText("Hi") when the Fragment is first created. You can find an example of creating a Fragment with arguments here.

Update

As noted in the lengthy comments although the first approach allows getChildFragmentManager().findFragmentByTag("year08") to return the fragment it is still not a good idea to call any methods on the Fragment that access its views until onViewStateRestored(...) or after has been called.

This is because when using the FragmentManager to add the parent fragment the child fragment's onCreateView method will not be called immediately after calling executePendingTransactions() so the child fragment's referenced views are null. If the parent Fragment is used directly in the layout this is not a problem as onCreateView of the child fragment is called as part of executePendingTransactions() and its views will not be null.

The best thing to do in this case would be to use the other approach as mentioned that uses Fragment arguments if you need to set initial values for views within fragments.

Community
  • 1
  • 1
George Mulligan
  • 11,813
  • 6
  • 37
  • 50
  • 02-09 22:30:07.148 7381-7381/com.compassasu.compass E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: com.compassasu.compass, PID: 7381 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference at com.compassasu.compass.Fragments.YearFragment08.setinfo(YearFragment08.java:27) Still didn't work unfortunately – Sherif Amr Feb 09 '16 at 20:32
  • Actually it did work as you now made it into the `setText` method of your `Fragment`. New issues is the `yearInfo` text view is `null` in your `setInfo` method. Are you sure it is assigned in the `onCreateView` method of `YearFragment08`? Double check the `year_frag08.xml` file for a `TextView` with `id=txt_yearInfo_08`. – George Mulligan Feb 10 '16 at 00:41
  • Do you know how to use a debugger? Put a break point in the `onCreateView` method and verify yourself the `TextView` cannot be found. If you don't know how remove `yearInfo.setText(data);` temporarily from the `setInfo` method. Replace it with a call to `Log.d("My Tag", "I made it here")` so you can see this fixes the problem in your original question. Set some static text using `android:text` on the `TextView` in the layout file so you can see if this view is shown once the `Fragment` appears onscreen. – George Mulligan Feb 10 '16 at 01:10
  • I finally found the issue you are likely facing by taking a closer look at the stack trace. Since you are using a `ViewPager` the parent fragment is not yet added to the layout so when you add the child fragment its `onCreateView` method has not been called yet. Because of this it would be best to move to using arguments as I mentioned in the answer to first display the text. However, move the code you currently have in `onActivityCreated` into the `onResume` method temporarily and it will work. – George Mulligan Feb 10 '16 at 01:27