Reputation: 43
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 .
Upvotes: 3
Views: 1035
Reputation: 11903
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.
Upvotes: 1