web-dev-qa-db-ja.com

XMLレイアウトでフラグメントを宣言する場合、どのようにそれをバンドルに渡しますか?

フラグメントに置き換えたアクティビティがあります。アクティビティは、アクティビティが表示するデータに関する追加情報を持つインテントを取りました。

アクティビティは、同じ動作を行うフラグメントの単なるラッパーになったので、タグを使用してXMLでフラグメントを宣言した場合、そのバンドルをフラグメントに取得するにはどうすればよいですか?

FragmentTransactionを使用してFragmentをViewGroupに入れると、Fragmentコンストラクターでこの情報を渡す機会が得られますが、フラグメントがXMLで定義されている状況については疑問に思っています。

59
Plantage

アクティビティは、同じ動作を行うフラグメントの単なるラッパーになったので、タグを使用してXMLでフラグメントを宣言した場合、そのバンドルをフラグメントに取得するにはどうすればよいですか?

できません。

ただし、FragmentManagerfindFragmentById()を呼び出してフラグメント後のインフレーションを取得してから、フラグメントでメソッドを呼び出してデータを関連付けることを歓迎します。明らかにsetArguments()にすることはできませんが、フラグメントは、他の何らかの手段(onSaveInstanceState()setRetainInstance(true)などによって、データ自体を保持して構成の変更を保持することができます。 )。

44
CommonsWare

カプセル化された方法ではありませんが、親アクティビティからバンドルを「プル」することになりました。

Bundle bundle = getActivity().getIntent().getExtras();
43
Oded Breiner

別のオプションは、フラグメントを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で宣言するほど簡潔で単純ではありませんが、フラグメントをより多く制御できるため、このアプローチに移行しました。

9
Zapnologica

Bundleを渡すことはできませんが、XMLを介してフラグメントにパラメーター(または属性)を渡すことができます。

プロセスは Viewカスタム属性の定義方法 に似ています。 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()
    }
}

etvoilá、フラグメント内のXML属性:)

制限事項:

  • Android Studio(現在)は、レイアウトXMLでこのような引数をオートコンプリートしません
  • Parcelableを渡すことはできませんが、Android Attributes
5
Daniele Segato

私が見る唯一の解決策は、データ交換チャネルとして引数を使用しないことです。代わりに、フラグメントを作成して、他の場所から必要な情報を取得します。コールバックして適切なアクティビティを取得し、一時ストレージメモリ、シングルトンオブジェクトなどを調べます。

役立つ可能性のある別の解決策は、関連しないオブジェクトが Otto のようにMediatorデザインパターンを介してメッセージを交換できるようにするフレームワークを採用することです。

3
Renascienza