Я просматривал документацию по вложенным фрагментам, лучшие практики и все возможные ссылки здесь, в StackOverflow. Я видел предложения избегать использования тега фрагмента в файлах макета и вместо этого добавлять их через транзакцию для плавных переходов.
Прежде чем реализовать его в своем приложении, я попробовал простой пример и обнаружил неожиданное поведение, дочерние фрагменты onCreateView() не вызываются. Я предполагаю, что мне что-то не хватает в моем понимании, поэтому я ищу совет/помощь, чтобы разобраться с этим.
Пример потока показан ниже: --
MainActivity содержит фрагмент (MessageFragment), а MessageFragment содержит дочерний фрагмент (MessageTextFragment).
Я добавляю дочерний фрагмент программно, используя транзакцию фрагмента. Но onCreateView дочернего фрагмента никогда не вызывается, из-за чего подвид не раздувается.
Я везде использую библиотеку поддержки v4 для фрагментов. Вот мой полный код: --
Файл MainActivity: --
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();
}
}
}
файл макета для 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>
Первый фрагмент: 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();
}
}
}
Макет MessageFragment (Framelayout — это контейнер для дочернего фрагмента)
<?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>
Это дочерний фрагмент
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;
}
и его макет
<?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 никогда не печатает строку: --
Log.d("MESSAGE_FRAGMENT", "onCreateView вложенного фрагмента");
и я получаю исключение нулевого указателя, когда пытаюсь использовать текстовое поле дочернего фрагмента, так как оно не завышено. В основном, я получаю нулевой указатель по адресу: --
((MessageEditFragment)фрагмент).getView().findViewById(R.id.message_edit_text);
NPE
. Добавьте операторы журнала вonCreateView(...)
иonActivityCreated(...)
для как дочерних, так и родительских фрагментов:Log.i("ParentFrag", "onCreateView(...) :::: Parent")
... еще 3 оператора журнала. Проверьте последовательность выполнения. Я подозреваю, что дочернийonCreateView(...)
называется после родительскогоonActivityCreated(...)
. Я могу предложить пару решений, если вы можете проверить это. - person Vikram   schedule 05.09.2015interface
сvoid onTextChanged(String);
. Пусть родительский фрагмент реализует этотinterface
и вносит свою лепту при вызове этого метода:bAction.setEnabled(!TextUtils.isEmpty(text) && !TextUtils.isEmpty(text.trim()));
. Измените методMessageEditFragment.newInstance()
, чтобы получить экземпляр этого интерфейса. Когда фрагмент будет готов (onActivityCreated()
), вызовите метод интерфейса и обновите состояниеbutton
. Это масштабируемое решение: если вам требуется «больше» связи между этими фрагментами, добавьте больше методов. - person Vikram   schedule 10.09.2015