web-dev-qa-db-ja.com

フラグメントのメンバー変数とsetArguments

Android Fragmentsのリファレンス(特に DialogFragment ))で、私が期待するものとは異なるいくつかのことを行うことに気付きました:

1)。コンストラクタではなくpublic static foo newInstance()メソッドを使用します。
2)。メンバー変数ではなくsetArgumentsを使用して、onCreateDialogに値を渡します。

リフレクションを使用する場合、newInstanceの方が好ましいように見えることを読みました。しかし、なぜそれらがバンドルを介してパラメーターを渡すのか本当に理解していません。ただし、メンバー変数を使用するほうが安全で(マップからフェッチするために文字列を使用しない)、オーバーヘッドが少なくなります。

何かご意見は?

66
oobayly

私もこれに遭遇し、インスタンスフィールドよりも引数Bundleを使用することのいくつかの利点を見つけました:

  • Bundleにある場合、Androidシステムはそれを認識しており、Fragmentを作成および破棄できます(必須のパラメーターなし/デフォルトコンストラクターと通常のライフサイクルメソッドを使用) 、そして引数バンドルをもう一度渡すだけです。このようにして、低メモリ破壊の傾向や最終的な向きの変更によって引数が失われることはありません(これは、回転の少ないエミュレータでの開発後、実際のデバイスに最初に展開するときにしばしば私に当たります)。

  • BundleのエクストラActivityをそのままレイアウトに埋め込まれたFragmentに渡すことができます。例えばActivity "フルスクリーン"を表示するFragmentがあり、何を表示/実行するかを知るためにいくつかのID(またはContentProvider URI)が必要な場合、これをよく使用します。渡す前にBundle(またはコピー)にデータを追加することさえあります。

    _@Override
    protected void onCreate(final Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
    
      if (savedInstanceState == null) { // not a re-creation
        final Bundle args = new Bundle(getIntent().getExtras());
        args.putInt(CoverImageFragment.BACKGROUND_RESOURCE, Android.R.color.black);
        final Fragment fragment = CoverImageFragment.newInstance(args);
        getSupportFragmentManager()
          .beginTransaction()
          .add(Android.R.id.content, fragment)
          .commit();
      }
    }
    _
  • Fragmentの開発方法をActivityの開発方法に近づけます。つまり、Bundleを「入力パラメーター、例外なし」として作成します。

あなたが言及した欠点については:

  • タイトなループでBundleをクエリすることはほとんどないため、オーバーヘッドは最小限であると思います。そのため、onCreate()onViewCreate()で引数データを一度取得します。などはそれほど悪くありません。

  • タイプセーフのために、BundleにはさまざまなgetXXXX()メソッドがすべてあります。また、何かが欠けている場合やオプションの場合は、オーバーロードしてデフォルト値を提供することもできます。

newInstance()メソッドについては、newおよびsetArguments()の呼び出しをFragmentにカプセル化する簡単な方法と考えています。 BundleFragmentの両方を一度に作成して、すぐに使えるFragmentインスタンスを返す追加のMyFragment newInstance(String singleIdOfWhatToDisplay)を提供することがあります。

48

これは非常に混乱する問題であることがわかりました(Androidランドスケープ)を散らかす多くの問題の1つ)。

setArguments()は、Fragmentsでパラメーターなしのコンストラクターを使用できるようにするというAndroidの非常に役に立たないニーズに対する回避策です。

私の混乱は波に包まれました。まず、Fragmentで自然にオーバーライドするメソッド(例:onCreateonCreateView)は、Bundleのを表すsavedInstanceStateパラメータを受け取ります。あなたのFragment。このインスタンスの状態には、明らかに[〜#〜] nothing [〜#〜]を使用して、setArguments()を介して保存し、getArguments()を介して取得する値をどのように処理してもかまいません。どちらもBundleを使用し、両方のBundlesは同じオーバーライドされたメソッド内でアクセスされる可能性が高く、どちらも相互に関係ありません。

次に、AndroidがsetArguments()を使用する方法が不明です。Androidは、パラメータなしのコンストラクタを呼び出してFragmentを再構築します回転しますが、Fragmentが作成されたときに最後に呼び出されたsetArguments()メソッドを呼び出します。

え?

すばらしいですが、本当です。パラメータなしのBundlesコンストラクタの必要性を補うために、これらすべてがsetArguments()狂気でFragmentを作成しています。

つまり、静的なnewInstanceメソッドを使用してFragmentを作成しています。

public MyFragment() {
    //satisfy Android
}

public static MyFragment newInstance(long record_id) {
    Log.d("MyFragment", "Putting " + record_id + " into newInstance");
    MyFragment f = new MyFragment();
    Bundle args = new Bundle();
    args.putLong("record_id", record_id);
    f.setArguments(args);
    return f;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    /**
     * Perform an immediate check of arguments,
     * which ARE NOT the same as the bundle used
     * for saved instance state.
     */
    Bundle args = getArguments();
    if(args != null) {
        record_id = args.getLong("record_id");
        Log.d("MyFragment", "found record_id of " + String.valueOf(record_id));
    }
    if(savedInstanceState != null) {
        //now do something with savedInstanceState
    }
}
19
rmirabelle

私はAndroidプログラミングにかなり慣れていますが、これは問題に対する私の現在の理解です:

フラグメントのコンストラクタcannotにはパラメータがあります。アクティビティが一時停止すると、フラグメントを解放できます。アクティビティが再開される前に、システムはコンストラクターを呼び出すフラグメントの新しいバージョンを作成します。デフォルト以外のコンストラクタが使用されている場合、AndroidはFragmentsコンストラクタへの引数のタイプと値が何であるかを知っているはずですか?

バンドルがリリースされたとは思いません。バンドルは正確に保持されるため、デフォルトのコンストラクターで再作成された後、フラグメントに戻すことができます。

Philipp Reichartは彼の投稿でこれを回避しました(実際には回避された以上です)。

9
WayneJ

引数にもう1つ欠点を追加したいのは、動的にフラグメントを作成する必要があることです。 xmlから作成した場合、引数はあまり機能しません。そして私はそれが本当に嫌いです。

2
havexz