I have been going through nested fragments documentation, best practices and all possible links here in StackOverflow. I have seen suggestions to avoid using fragment tag in layout files and instead add them via transaction for seamless transitions.
Before implementing it in my app, I tried a simple example and I found some unexpected behavior, child fragments onCreateView() is not getting called. I assume that , I am missing something in my understanding, so I am looking for some advice/help to sort this out.
The example flow is as below:--
MainActivity hosts a fragment(MessageFragment) and the MessageFragment hosts a child fragment(MessageTextFragment).
I add the child fragment programatically using fragment transaction. But onCreateView of the child fragment never gets called, because of which the sub-view is not inflated.
I am using v4 support library for fragments everywhere Here is my complete code:--
MainActivity file:--
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.root_layout);
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = null;
if (savedInstanceState == null) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragment=new MessageFragment().newInstance();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}
}
}
layout file for MainActivity:-
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/wizard_layout_root"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:orientation="vertical">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_height="fill_parent"
android:layout_width="fill_parent"/>
</RelativeLayout>
The first Fragment is: MessageFragment--
public class MessageFragment extends Fragment {
private EditText msgText;
private Activity activity;
TextView tvTitle, tvContent, tvIntro;
Button bAction;
public static MessageFragment newInstance() {
MessageFragment f = new MessageFragment();
return (f);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.message, container, false);
tvTitle = (TextView) view.findViewById(R.id.fragment_title);
tvIntro = (TextView) view.findViewById(R.id.fragment_intro);
tvContent = (TextView) view.findViewById(R.id.fragment_contents);
bAction = (Button) view.findViewById(R.id.fragment_action);
Fragment fragment = getChildFragmentManager().findFragmentById(R.id.sms_message);
if (fragment == null) {
Log.d("MESSAGE_FRAGMENT", "definetly inside");
fragment = MessageEditFragment.newInstance();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.sms_message, fragment);
transaction.commit();
getChildFragmentManager().executePendingTransactions();
Log.d("MESSAGE_FRAGMENT", "" + getChildFragmentManager().findFragmentById(R.id.sms_message));
}
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activity = getActivity();
if (activity != null) {
Fragment fragment = getChildFragmentManager().findFragmentById(R.id.sms_message);
Log.d("MESSAGE_FRAGMENT", "onActivityCreated" + fragment);
msgText = (EditText) ((MessageEditFragment)fragment).getView().findViewById(R.id.message_edit_text);
bAction.setEnabled(!msgText.getText().toString().trim().equals(""));
msgText.selectAll();
}
}
}
Layout of MessageFragment(Framelayout is the container for child fragment)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
android:orientation="vertical">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/fragment_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"/>
<TextView
android:id="@+id/fragment_intro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/fragment_title" />
<LinearLayout
android:id="@+id/ll_message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/fragment_intro"
android:layout_weight="1">
<FrameLayout
android:id="@+id/sms_message"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
<Button
android:id="@+id/fragment_action"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/ll_message"/>
</RelativeLayout>
</ScrollView>
</LinearLayout>
This is the child fragment
public class MessageEditFragment extends Fragment {
private EditText messageEditText;
private MessageLimitWatcher messageLimitWatcher;
private int maxCharacters;
private String messageHeader;
private Button bAction;
public static MessageEditFragment newInstance() {
MessageEditFragment f = new MessageEditFragment();
return(f);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d("MESSAGE_FRAGMENT", "onCreateView Of nested fragment");
View view = inflater.inflate(R.layout.message_fragment, container, false);
messageEditText = (EditText) view.findViewById(R.id.message_edit_text);
messageEditText.requestFocus();
return view;
}
and its layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_width="fill_parent">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="130dp">
<EditText
android:id="@+id/message_edit_text"
android:layout_height="130dp"
android:layout_width="fill_parent" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/black"/>
</RelativeLayout>
</LinearLayout>
Logcat never prints the line:--
Log.d("MESSAGE_FRAGMENT", "onCreateView Of nested fragment");
and I get a nullpointer exception when I try to use the text field of child fragment, as it is not inflated.So basically, I get nullpointer at:--
((MessageEditFragment)fragment).getView().findViewById(R.id.message_edit_text);
Don't call the transactions inside of onCreateView
either use onActivityCteated
or onCreate
.
Also worth noting don't call, executePendingTransactions
when you are inside a of the parent fragment, that is bound to break something.
Try to setup your parent fragment something like this:
public class MessageFragment extends Fragment {
private EditText msgText;
private Activity activity;
TextView tvTitle, tvContent, tvIntro;
Button bAction;
public static MessageFragment newInstance() {
MessageFragment f = new MessageFragment();
return (f);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.message, container, false);
tvTitle = (TextView) view.findViewById(R.id.fragment_title);
tvIntro = (TextView) view.findViewById(R.id.fragment_intro);
tvContent = (TextView) view.findViewById(R.id.fragment_contents);
bAction = (Button) view.findViewById(R.id.fragment_action);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activity = getActivity();
if (activity != null) {
Fragment fragment = getChildFragmentManager().findFragmentById(R.id.sms_message);
Log.d("MESSAGE_FRAGMENT", "onActivityCreated" + fragment);
msgText = (EditText) ((MessageEditFragment)fragment).getView().findViewById(R.id.message_edit_text);
bAction.setEnabled(!msgText.getText().toString().trim().equals(""));
msgText.selectAll();
}
Fragment fragment = MessageEditFragment.newInstance();
getChildFragmentManager().beginTransaction()
.replace(R.id.sms_message, fragment)
.commit();
}
}
Maybe you should not add child fragment(say call transaction.add
within a fragment).
Do fragment transaction only on Activity.
When you want to do fragment transaction, you could notify the Activity hosting the current fragment, through EventBus, or an interface implemented by the host Activity.
来源:https://stackoverflow.com/questions/32240138/oncreateview-of-nested-fragment-is-not-called