OnCreateView() вложенного фрагмента не вызывается

Я просматриваю документацию вложенных фрагментов, лучшие практики и все возможные ссылки здесь, в 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 вложенного фрагмента" );

и я получаю исключение nullpointer, когда пытаюсь использовать текстовое поле дочернего фрагмента, так как оно не завышено. Поэтому в основном я получаю nullpointer в: -

((MessageEditFragment) фрагмент).getView() findViewById (R.id.message_edit_text);.

Ответ 1

Не вызывайте транзакции внутри onCreateView или используйте onActivityCteated или onCreate.

Также стоит отметить, что не вызывайте executePendingTransactions, когда вы находитесь внутри родительского фрагмента, который должен что-то сломать.

Попробуйте настроить родительский фрагмент примерно так:

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();
  }
}

Ответ 2

Возможно, вам не следует добавлять дочерний фрагмент (например, вызов transaction.add внутри фрагмента).

Делать операцию фрагмента только для Activity.

Если вы хотите выполнить транзакцию фрагмента, вы можете уведомить об активности хостинга текущего фрагмента через EventBus или интерфейс, реализованный хост-актив.