Подтвердить что ты не робот

Если я объявляю фрагмент в XML-макете, как передать его Bundle?

У меня есть действие, которое я заменил фрагментом. Эта деятельность приняла намерение, в котором была дополнительная информация о том, какие данные должна была отображаться.

Теперь, когда моя активность является всего лишь оберткой вокруг фрагмента, которая выполняет ту же работу, как мне получить этот пакет для фрагмента, если я объявляю фрагмент в XML с тегом?

Если бы я использовал FragmentTransaction, чтобы поместить Fragment в ViewGroup, я бы получил возможность передать эту информацию в конструкторе фрагмента, но мне интересно, где фрагмент определен в XML.

4b9b3361

Ответ 1

Теперь, когда моя активность является всего лишь оберткой вокруг фрагмента, которая выполняет ту же работу, как мне получить этот пакет для фрагмента, если я объявляю фрагмент в XML с тегом?

Вы не можете.

Однако вы можете вызвать findFragmentById() на FragmentManager, чтобы получить фрагмент после инфляции, а затем вызвать некоторый метод для фрагмента, чтобы связать с ним данные. Хотя, по-видимому, это не может быть setArguments(), ваш фрагмент может организовать хранение данных непосредственно после изменения конфигурации другими способами (onSaveInstanceState(), setRetainInstance(true) и т.д.).

Ответ 2

Это не инкапсулированный путь, но я закончил "вытягивание" пакета из родительской активности:

Bundle bundle = getActivity().getIntent().getExtras();

Ответ 3

Другой вариант - не объявлять фрагмент в XML. Я знаю, что это не совсем то, что вы хотите сделать. Однако вы можете объявить простой макет в вашем представлении следующим образом:

    <LinearLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" />

А затем в вашем классе Activity вы программно раздуваете макет фрагментом. Таким образом, вы можете проходить через параметры с помощью аргументов.

 FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    MyFragment fragment = MyFragment.newInstance();
    Bundle args = new Bundle();
    args.putInt(Global.INTENT_INT_ROLE, 1);
    fragment.setArguments(args);
    fragmentTransaction.add(R.id.fragment_container, fragment, "MyActivity");
    fragmentTransaction.commit();

Этот подход не так чист и прост, как объявление его в XML, однако я перешел к нему, так как он дает вам гораздо больший контроль над фрагментом.

Ответ 4

Вы не можете передать Bundle (если вы не раздули фрагмент программно, а не через XML), но вы МОЖЕТЕ передать параметры (или, скорее, атрибуты) через XML фрагменту.

Процесс похож на как вы определяете Просмотр пользовательских атрибутов. За исключением AndroidStudio (в настоящее время) не помочь вам в этом процессе.

предположим, что это ваш фрагмент с аргументами (я буду использовать kotlin, но он полностью работает и в Java):

class MyFragment: Fragment() {

    // your fragment parameter, a string
    private var screenName: String? = null

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        if (screenName == null) {
            screenName = arguments?.getString("screen_name")
        }
    }
}

И вы хотите сделать что-то вроде этого:

<fragment
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/myFragment"
    android:name="com.example.MyFragment"
    app:screen_name="@string/screen_a"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

Обратите внимание на app:screen_name="@string/screen_a"

чтобы это работало, просто добавьте это в файл значений (fragment_attrs.xml или выберите любое имя):

<!-- define your attribute name and type -->
<attr name="screen_name" format="string|reference"/>

<!-- define a bunch of constants you wanna use -->
<string name="screen_a" translatable="false">ScreenA</string>
<string name="screen_b" translatable="false">ScreeenB</string>

<!-- now define which arguments your fragment is gonna have (can be more then one) -->
<!-- the convention is "FragmentClassName_MembersInjector" -->
<declare-styleable name="MyFragment_MembersInjector">
    <attr name="screen_name"/>
</declare-styleable>

Почти готово, вам просто нужно прочитать его в своем фрагменте, поэтому добавьте метод:

override fun onInflate(context: Context?, attrs: AttributeSet?, savedInstanceState: Bundle?) {
    super.onInflate(context, attrs, savedInstanceState)
    if (context != null && attrs != null && screenName == null) {
        val ta = context.obtainStyledAttributes(attrs, R.styleable.MyFragment_MembersInjector)
        if (ta.hasValue(R.styleable.MyFragment_MembersInjector_screen_name)) {
            screenName = ta.getString(R.styleable.MyFragment_MembersInjector_screen_name)
        }
        ta.recycle()
    }
}

et voilá, ваши атрибуты XML в вашем фрагменте :)

Ограничения:

  • Android Studio (на данный момент) не выполняет автозаполнение таких аргументов в макете XML
  • Вы не можете передать Parcelable, но только то, что можно определить как атрибуты Android

Ответ 5

Единственное решение, которое я вижу, - не использовать аргументы в качестве канала обмена данными. Вместо этого сделайте свой фрагмент для получения необходимой информации из другого места. Перезвоните, чтобы получить правильную активность, проконсультироваться с памятью временного хранения, объектом Singleton и т.д.

Другим решением, которое может быть полезно, является использование фреймворков, которые позволяют несвязанным объектам обмениваться сообщениями с помощью шаблона проектирования посредника, как Otto.