DialogFragmentからフラグメントへのコールバック


159

質問:DialogFragmentから別のFragmentへのコールバックをどのように作成しますか?私の場合、関係するアクティビティはDialogFragmentを完全に認識していないはずです。

私が持っていると考えて

public class MyFragment extends Fragment implements OnClickListener

その後、いくつかの点で私はできません

DialogFragment dialogFrag = MyDialogFragment.newInstance(this);
dialogFrag.show(getFragmentManager, null);

MyDialogFragmentは次のようになります

protected OnClickListener listener;
public static DialogFragment newInstance(OnClickListener listener) {
    DialogFragment fragment = new DialogFragment();
    fragment.listener = listener;
    return fragment;
}

ただし、DialogFragmentがそのライフサイクルを通じて一時停止および再開した場合にリスナーが存在するという保証はありません。フラグメントの唯一の保証は、setArgumentsとgetArgumentsを介してバンドルを介して渡されたものです。

リスナーである必要がある場合、アクティビティを参照する方法があります。

public Dialog onCreateDialog(Bundle bundle) {
    OnClickListener listener = (OnClickListener) getActivity();
    ....
    return new AlertDialog.Builder(getActivity())
        ........
        .setAdapter(adapter, listener)
        .create();
}

しかし、アクティビティでイベントをリッスンしたくないので、フラグメントが必要です。実際には、OnClickListenerを実装する任意のJavaオブジェクトにすることができます。

DialogFragmentを介してAlertDialogを表示するFragmentの具体例を考えてみましょう。はい/いいえボタンがあります。これらのボタンプレスを、それを作成したフラグメントに送信するにはどうすればよいですか?


「しかし、DialogFragmentがそのライフサイクルを通じて一時停止および再開した場合に、リスナーが待機しているという保証はありません。」onDestroy()の実行中にフラグメントの状態が破壊されると思いましたか?あなたは正しいはずですが、私は今フラグメント状態を使用する方法を少し混乱しています。あなたが言った問題をどのように再現しますか、リスナーは周りにいませんか?
Sean

OnClickListener listener = (OnClickListener) getParentFragment();代わりにDialogFragmentで単純に使用できない理由はわかりません。メインのFragmentは、最初に行ったようにインターフェイスを実装します。
キルカ2015

ここでは無関係な質問への答えですが、それはこれがきれいな方法の中でどのように行われるかをお見せしstackoverflow.com/questions/28620026/...
user2288580

回答:


190

関連するアクティビティは、DialogFragmentを完全に認識していません。

フラグメントクラス:

public class MyFragment extends Fragment {
int mStackLevel = 0;
public static final int DIALOG_FRAGMENT = 1;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) {
        mStackLevel = savedInstanceState.getInt("level");
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("level", mStackLevel);
}

void showDialog(int type) {

    mStackLevel++;

    FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction();
    Fragment prev = getActivity().getFragmentManager().findFragmentByTag("dialog");
    if (prev != null) {
        ft.remove(prev);
    }
    ft.addToBackStack(null);

    switch (type) {

        case DIALOG_FRAGMENT:

            DialogFragment dialogFrag = MyDialogFragment.newInstance(123);
            dialogFrag.setTargetFragment(this, DIALOG_FRAGMENT);
            dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");

            break;
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch(requestCode) {
            case DIALOG_FRAGMENT:

                if (resultCode == Activity.RESULT_OK) {
                    // After Ok code.
                } else if (resultCode == Activity.RESULT_CANCELED){
                    // After Cancel code.
                }

                break;
        }
    }
}

}

DialogFragmentクラス:

public class MyDialogFragment extends DialogFragment {

public static MyDialogFragment newInstance(int num){

    MyDialogFragment dialogFragment = new MyDialogFragment();
    Bundle bundle = new Bundle();
    bundle.putInt("num", num);
    dialogFragment.setArguments(bundle);

    return dialogFragment;

}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {

    return new AlertDialog.Builder(getActivity())
            .setTitle(R.string.ERROR)
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setPositiveButton(R.string.ok_button,
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, getActivity().getIntent());
                        }
                    }
            )
            .setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_CANCELED, getActivity().getIntent());
                }
            })
            .create();
}
}

100
私はここで重要だと思うsetTargetFragmentgetTargetFragment。の使用onActivityResultは少し不明確です。onActivityResultを転用するのではなく、Fragment呼び出し元で独自の特定のメソッドを宣言して使用する方がおそらく良いでしょう。しかし、その時点でのすべてのセマンティクス。
eternalmatt 2013年

2
スタックレベル変数は使用されていませんか?
表示名

6
これは構成変更-ローテーションに耐えますか?
Maxrunner 2014年

3
これを使用しました。注:ローテーションやスリープを切り抜けるのにスタックレベルは必要ありませんでした。onActivityResultの代わりに、私のフラグメントはDialogResultHandler#handleDialogResult(私が作成したインターフェース)を実装しています。@myCodeは、ダイアログで選択された値がIntentに追加され、onActivityResultの内部を読み取るのに非常に役立ちます。初心者には意図がわかりません。
Chris Betti、2014

7
@eternalmatt、あなたの異論は完全に合理的ですが、onActivityResult()の値はどのFragmentにも存在することが保証されているため、どのFragmentも親として使用できると思います。独自のインターフェースを作成し、それを親Fragmentに実装させる場合、子はそのインターフェースを実装する親でのみ使用できます。後でその子をより広く使用し始めると、そのインターフェースに子を結合すると、再びあなたを悩ませることになるかもしれません。「組み込み」のonActivityResult()インターフェースを使用する場合、追加のカップリングは必要ないため、柔軟性が少し向上します。
ダルベルギア2015

78

TargetFragmentソリューションはIllegalStateException、アプリケーションが破棄されて再作成された後に作成される可能性があるため、ダイアログフラグメントの最適なオプションとは思われません。この場合FragmentManager、ターゲットフラグメントを見つけることができず、次のIllegalStateExceptionようなメッセージが表示されます。

「キーandroid:target_state:index 1のフラグメントは存在しません」

Fragment#setTargetFragment()子フラグメントと親フラグメントの間の通信ではなく、兄弟フラグメント間の通信を目的としているようです。

したがって、別の方法はChildFragmentManager、アクティビティを使用するのではなく、親フラグメントのを使用してこのようなダイアログフラグメントを作成することFragmentManagerです。

dialogFragment.show(ParentFragment.this.getChildFragmentManager(), "dialog_fragment");

そして、インターフェイスを使用することにより、onCreateメソッドでDialogFragment親フラグメントを取得できます:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        callback = (Callback) getParentFragment();
    } catch (ClassCastException e) {
        throw new ClassCastException("Calling fragment must implement Callback interface");
    }
}

あとは、これらの手順の後でコールバックメソッドを呼び出すだけです。

この問題の詳細については、https//code.google.com/p/android/issues/detail?id = 54520のリンクを確認して ください。


2
また、これは、API 23に追加導入ONATTACH(コンテキストコンテキスト)で動作します
サンタTeclado

1
これが受け入れられる答えです。現在受け入れられている答えはバグが多く、フラグメントはこのように使用することを意図していません。
NecipAllef

3
@AhmadFadliここでの問題は、フラグメント間の通信に適切なコンテキスト(親)を取得することです。ダイアログフラグメントをアクティビティの子として使用する場合は、混乱することはないはずです。コールバックを取得するためのActivityおよびgetActivity()のFragmentManagerで十分です。
Oguz Ozcan

1
これは受け入れられる答えになるはずです。それは明確に説明され、詳細に説明されています。それは単に人々に投げかけられるコードではありません。
ビンス

1
@lukecross ParentFragmentは、DialogFragment(show()を呼び出すもの)を作成するフラグメントですが、childFragmentManagerが再構成/画面の回転を存続しないようです...
iwat0qs

34

私はこれを行うためにこの簡単な手順に従いました。

  1. のようなDialogFragmentCallbackInterfaceいくつかのメソッドのようなインターフェースを作成しますcallBackMethod(Object data)。データを渡すために呼び出すもの。
  2. 今、あなたはDialogFragmentCallbackInterfaceあなたのフラグメントにインターフェースを実装することができますMyFragment implements DialogFragmentCallbackInterface
  3. DialogFragment作成時に、呼び出しフラグメントMyFragmentを、作成したターゲットフラグメントとしてチェックセットターゲットフラグをDialogFragment使用して設定します(フラグメントフラグメント、int requestCode)myDialogFragment.setTargetFragment(this, 0)

    MyDialogFragment dialogFrag = new MyDialogFragment();
    dialogFrag.setTargetFragment(this, 1); 
    
  4. DialogFragment呼び出してターゲットフラグメントオブジェクトを取得し、にgetTargetFragment()キャストDialogFragmentCallbackInterfaceします。これで、このインターフェイスを使用してデータをフラグメントに送信できます。

    DialogFragmentCallbackInterface callback = 
               (DialogFragmentCallbackInterface) getTargetFragment();
    callback.callBackMethod(Object data);
    

    これですべて完了です。このインターフェースをフラグメントに実装したことを確認してください。


4
これが最良の答えです。すばらしい答えです。
Ms. Sajedul Karim 2016

また、ソースフラグメントと宛先フラグメントの両方に同じフラグメントマネージャーを使用してください。そうしないと、getTargetFragmentが機能しません。したがって、childFragmentManagerを使用している場合、ソースフラグメントは子フラグメントマネージャーによってコミットされないため、機能しません。これら2つのフラグメントは、親/子フラグメントではなく兄弟フラグメントと考えるのが最善です。
Thupten

率直に言って、2つの兄弟フラグメント間で通信する場合は、ターゲットフラグメントパターンのみを使用する方が良いです。リスナーを持たないことで、fragment2のfragment1を誤ってリークすることを回避できます。ターゲットフラグメントを使用する場合は、リスナー/コールバックを使用しないでください。onActivityResult(request code, resultcode, intent)結果をfragment1に返すためにのみ使用します。fragment1から、setTargetFragment()およびfragment2から、を使用しますgetTargetFragment()。親/子フラグメントを使用してフラグメント化したり、アクティビティをフラグメント化したりする場合は、リスナーまたはコールバックを使用できます。これは、子フラグメントの親をリークする危険がないためです。
13

@Thuptenが「リーク」と言った場合、それはメモリリークまたは「リーク実装の詳細」を意味しますか?Vijayの答えがメモリをリークすることは、戻り値にonActivityResultyを使用すること以上にはないと思います。どちらのパターンもターゲットフラグメントへの参照を保持します。実装の詳細をリークすることを意味する場合、彼のパターンはonActivityResultよりも優れていると思います。コールバックメソッドは明示的です(正しく名前が付けられている場合)。取得したすべてがOKでキャンセルされた場合、最初のフラグメントはそれらの意味を解釈する必要があります。
tir38

34

少し遅いかもしれませんが、私と同じように同じ質問で他の人を助けるかもしれません。

表示する前にsetTargetFragmenton を使用しDialog、ダイアログでgetTargetFragment参照を取得するために呼び出すことができます。


ここで別の質問への答えですが、それはまた、あなたの質問に適用され、クリーンなソリューションです:stackoverflow.com/questions/28620026/...
user2288580

IllegalStateException to me
luke cross

19

他のフラグメントと通信ガイドでは、フラグメントは関連するアクティビティを通じて通信する必要があると述べています。

多くの場合、たとえばユーザーイベントに基づいてコンテンツを変更するために、1つのフラグメントが別のフラグメントと通信する必要があります。すべてのフラグメントからフラグメントへの通信は、関連付けられたアクティビティを介して行われます。2つのフラグメントが直接通信することはありません。


1
内部フラグメントについてはどうですか。つまり、別のフラグメント内のフラグメントがホストフラグメントと通信する方法
Ravi

@Ravi:各フラグメントは、getActivity()を呼び出して、すべてのフラグメントに共通のアクティビティと通信する必要があります。
Edward Brey 2013年

1
@Chris:フラグメントに継続的な通信が必要な場合は、実装する適切なフラグメントごとにインターフェースを定義します。その後、アクティビティの仕事は、対応するフラグメントへのインターフェースポインターをフラグメントに提供することに限定されます。その後、フラグメントはインターフェースを介して「直接」安全に通信できます。
エドワードブレイ

3
フラグメントの使用が拡大されたため、直接フラグメント通信を使用しないという元々の考え方は崩れていると思います。たとえば、ナビゲーションドロワーでは、アクティビティの直接の子フラグメントはそれぞれ、おおまかにアクティビティとして機能しています。したがって、dialogfragmentなどのフラグメントがアクティビティを介して通信すると、読みやすさ/柔軟性IMOに悪影響を及ぼします。実際、dialogfragmentをカプセル化して、再利用可能な方法でアクティビティとフラグメントの両方を処理できるようにするための素晴らしい方法はないようです。
Sam

16
私はこれが古いことを知っていますが、他の誰かがここに来る場合、そのドキュメントで説明されているケースは、1つのフラグメントがDialogFragmentの作成と管理を決定するために使用されるロジックを「所有」している場合は適用されないように感じます。アクティビティがダイアログが作成される理由や、どのような条件下で却下する必要があるかさえわからない場合に、フラグメントからアクティビティへの一連の接続を作成するのは奇妙なことです。その上、DialogFragmentは非常にシンプルで、ユーザーに通知して応答を取得するためだけに存在します。
Chris

12

interfaceフラグメントクラスでを定義し、そのインターフェースを親アクティビティに実装する必要があります。詳細については、http://developer.android.com/guide/components/fragments.html#EventCallbacksをご覧ください。コードは次のようになります。

断片:

public static class FragmentA extends DialogFragment {

    OnArticleSelectedListener mListener;

    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        }
    }
}

アクティビティ:

public class MyActivity extends Activity implements OnArticleSelectedListener{

    ...
    @Override
    public void onArticleSelected(Uri articleUri){

    }
    ...
}

1
私はあなたが文書をすくい取りすぎたと思います。これらのコードセグメントは両方ともでありFragmentA、彼はアクティビティがOnArticleSelectedListenerを開始したフラグメントではなくであると想定しています。
eternalmatt

2
私があなたが悪い練習をしようとしていることを考えます。Androidガイドラインでは、フラグメントからフラグメントへのすべての通信がアクティビティを通じて行われることをお勧めしています(developer.android.com/training/basics/fragments/…ごと)。本当にすべてを処理しMyFragmentたい場合は、通常の方法に切り替えることをお勧めしますAlertDialog
James McCracken

1
フラグメントが互いに直接対話することの懸念は、一部のレイアウトではすべてのフラグメントがロードされない可能性があり、例に示すように、フラグメントを切り替える必要があるかもしれないということです。フラグメントからダイアログフラグメントを起動することについて話すとき、その懸念は有効ではないと思います。

私はこれを自分の活動に実装しています。質問:フラグメントがこのダイアログをインスタンス化できるように、このソリューションを拡張できますか?
Bill Mote

1
これは、アーキテクチャーの観点からは良い習慣であり、そのため受け入れられるべき答えです。onActivityResultを使用すると、スパゲッティアーキテクチャにつながります
Bruno Carrier

4

リスナをフラグメントに設定する正しい方法は、アタッチされたときに設定することです。私が抱えていた問題は、onAttachFragment()が呼び出されなかったことです。調査の結果、getChildFragmentManagerではなくgetFragmentManagerを使用していたことがわかりました。

ここに私がそれをする方法があります:

MyDialogFragment dialogFragment = MyDialogFragment.newInstance("title", "body");
dialogFragment.show(getChildFragmentManager(), "SOME_DIALOG");

onAttachFragmentに添付します。

@Override
public void onAttachFragment(Fragment childFragment) {
    super.onAttachFragment(childFragment);

    if (childFragment instanceof MyDialogFragment) {
        MyDialogFragment dialog = (MyDialogFragment) childFragment;
        dialog.setListener(new MyDialogFragment.Listener() {
            @Override
            public void buttonClicked() {

            }
        });
    }
}

3

公式ドキュメントによると:

Fragment#setTargetFragment

このフラグメントのオプションのターゲット。これは、たとえば、このフラグメントが別のフラグメントによって開始されていて、完了したときに最初の結果を返したい場合に使用できます。ここで設定されたターゲットは、FragmentManager#putFragmentを介してインスタンス間で保持されます。

Fragment#getTargetFragment

setTargetFragment(Fragment、int)によって設定されたターゲットフラグメントを返します。

だからあなたはこれを行うことができます:

// In your fragment

public class MyFragment extends Fragment implements OnClickListener {
    private void showDialog() {
        DialogFragment dialogFrag = MyDialogFragment.newInstance(this);
        // Add this
        dialogFrag.setTargetFragment(this, 0);
        dialogFrag.show(getFragmentManager, null);
    }
    ...
}

// then

public class MyialogFragment extends DialogFragment {
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        // Then get it
        Fragment fragment = getTargetFragment();
        if (fragment instanceof OnClickListener) {
            listener = (OnClickListener) fragment;
        } else {
            throw new RuntimeException("you must implement OnClickListener");
        }
    }
    ...
}

説明できますか?
Yilmaz

この場合、「MyFragment」参照を「MyialogFragment」に渡す必要があり、「Fragment」はそれを行うためのメソッドを提供します。公式ドキュメントの説明を追加しました。私よりもはっきりと言うべきです。
SUPERYAO

2

私も同様の問題に直面していました。私が見つけた解決策は:

  1. James McCrackenが上記で説明したように、DialogFragmentでインターフェースを宣言します。

  2. アクティビティにインターフェースを実装します(フラグメントではありません!これは良い方法ではありません)。

  3. アクティビティのコールバックメソッドから、実行したいジョブを実行するフラグメント内の必要なパブリック関数を呼び出します。

したがって、これは2段階のプロセスになります。DialogFragment-> Activity、次にActivity-> Fragment


1

フラグメントLiveWallFilterFragment(受信フラグメント)からフラグメントダッシュボードLiveWall(呼び出しフラグメント)に結果を取得しています...

 LiveWallFilterFragment filterFragment = LiveWallFilterFragment.newInstance(DashboardLiveWall.this ,"");

 getActivity().getSupportFragmentManager().beginTransaction(). 
 add(R.id.frame_container, filterFragment).addToBackStack("").commit();

どこ

public static LiveWallFilterFragment newInstance(Fragment targetFragment,String anyDummyData) {
        LiveWallFilterFragment fragment = new LiveWallFilterFragment();
        Bundle args = new Bundle();
        args.putString("dummyKey",anyDummyData);
        fragment.setArguments(args);

        if(targetFragment != null)
            fragment.setTargetFragment(targetFragment, KeyConst.LIVE_WALL_FILTER_RESULT);
        return fragment;
    }

setResultを呼び出しフラグメントに戻します

private void setResult(boolean flag) {
        if (getTargetFragment() != null) {
            Bundle bundle = new Bundle();
            bundle.putBoolean("isWorkDone", flag);
            Intent mIntent = new Intent();
            mIntent.putExtras(bundle);
            getTargetFragment().onActivityResult(getTargetRequestCode(),
                    Activity.RESULT_OK, mIntent);
        }
    }

onActivityResult

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == KeyConst.LIVE_WALL_FILTER_RESULT) {

                Bundle bundle = data.getExtras();
                if (bundle != null) {

                    boolean isReset = bundle.getBoolean("isWorkDone");
                    if (isReset) {

                    } else {
                    }
                }
            }
        }
    }

1

更新しました:

私が使用して、あなたのためにそれらの鋳物を生成し、私の要旨コードに基づいてライブラリを作っ@CallbackFragmentして@Callback

https://github.com/zeroarst/callbackfragment

また、この例では、フラグメントから別のフラグメントにコールバックを送信する例を示しています。

古い答え:

私が作っBaseCallbackFragmentおよび注釈を@FragmentCallback。それは現在拡張していますFragment、あなたはそれをに変えることができて、DialogFragmentそして働くでしょう。次の順序で実装をチェックします:getTargetFragment()> getParentFragment()> context(activity)。

次に、それを拡張してフラグメントでインターフェースを宣言し、それに注釈を付けるだけで、あとはベースフラグメントが行います。アノテーションにはmandatory、フラグメントにコールバックを実装させるかどうかを決定するためのパラメーターもあります。

public class EchoFragment extends BaseCallbackFragment {

    private FragmentInteractionListener mListener;

    @FragmentCallback
    public interface FragmentInteractionListener {
        void onEcho(EchoFragment fragment, String echo);
    }
}

https://gist.github.com/zeroarst/3b3f32092d58698a4568cdb0919c9a93


1

Kotlinの皆さん、こんにちは!

したがって、問題はMainActivity、アクティビティを作成し、そのアクティビティでフラグメントを作成したことです。次に、それFragmentAFragmentA呼び出す上にダイアログフラグメントを作成しますFragmentB。経由せずにFragmentB戻ることで結果をどのように取得できますか?FragmentAMainActivity

注意:

  1. FragmentAはの子フラグメントですMainActivity。で作成されたフラグメントを管理するには、FragmentAそれを使用childFragmentManagerします!
  2. FragmentAの親フラグメントです。内部FragmentBからアクセスFragmentAするにFragmentBは、を使用しますparenFragment

そうは言っても、内部ではFragmentA

class FragmentA : Fragment(), UpdateNameListener {
    override fun onSave(name: String) {
        toast("Running save with $name")
    }

    // call this function somewhere in a clickListener perhaps
    private fun startUpdateNameDialog() {
        FragmentB().show(childFragmentManager, "started name dialog")
    }
}

これがダイアログの断片FragmentBです。

class FragmentB : DialogFragment() {

    private lateinit var listener: UpdateNameListener

    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
            listener = parentFragment as UpdateNameListener
        } catch (e: ClassCastException) {
            throw ClassCastException("$context must implement UpdateNameListener")
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            val builder = AlertDialog.Builder(it)
            val binding = UpdateNameDialogFragmentBinding.inflate(LayoutInflater.from(context))
            binding.btnSave.setOnClickListener {
                val name = binding.name.text.toString()
                listener.onSave(name)
                dismiss()
            }
            builder.setView(binding.root)
            return builder.create()
        } ?: throw IllegalStateException("Activity can not be null")
    }
}

2つをリンクするインターフェースは次のとおりです。

interface UpdateNameListener {
    fun onSave(name: String)
}

それでおしまい。


1
私はこのドキュメントをフォローしました:developer.android.com/guide/topics/ui/dialogsとそれは動作しませんでした。どうもありがとうございます。このparentfragmentが毎回期待どおりに機能することを願っています:)
UmutTekin

1
onDetach内でリスナーをnullに設定することを忘れないでください:)
BekaBot

@BekaBotコメントありがとうございます。私はいくつかの調査を行いましたが、リスナーを閉じる必要はないようです。stackoverflow.com/a/37031951/10030693
Ssenyonjo

0

私はRxAndroidでエレガントな方法でこれを解決しました。DialogFragmentのコンストラクターでオブザーバーを受け取り、observableにサブスクライブして、コールバックが呼び出されたときに値をプッシュします。次に、FragmentでObserverの内部クラスを作成し、インスタンスを作成して、DialogFragmentのコンストラクターに渡します。メモリリークを回避するためにオブザーバーでWeakReferenceを使用しました。これがコードです:

BaseDialogFragment.java

import java.lang.ref.WeakReference;

import io.reactivex.Observer;

public class BaseDialogFragment<O> extends DialogFragment {

    protected WeakReference<Observer<O>> observerRef;

    protected BaseDialogFragment(Observer<O> observer) {
        this.observerRef = new WeakReference<>(observer);
   }

    protected Observer<O> getObserver() {
    return observerRef.get();
    }
}

DatePickerFragment.java

public class DatePickerFragment extends BaseDialogFragment<Integer>
    implements DatePickerDialog.OnDateSetListener {


public DatePickerFragment(Observer<Integer> observer) {
    super(observer);
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    // Use the current date as the default date in the picker
    final Calendar c = Calendar.getInstance();
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH);
    int day = c.get(Calendar.DAY_OF_MONTH);

    // Create a new instance of DatePickerDialog and return it
    return new DatePickerDialog(getActivity(), this, year, month, day);
}

@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
        if (getObserver() != null) {
            Observable.just(month).subscribe(getObserver());
        }
    }
}

MyFragment.java

//Show the dialog fragment when the button is clicked
@OnClick(R.id.btn_date)
void onDateClick() {
    DialogFragment newFragment = new DatePickerFragment(new OnDateSelectedObserver());
    newFragment.show(getFragmentManager(), "datePicker");
}
 //Observer inner class
 private class OnDateSelectedObserver implements Observer<Integer> {

    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(Integer integer) {
       //Here you invoke the logic

    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onComplete() {

    }
}

あなたはここでソースコードを見ることができます:https//github.com/andresuarezz26/carpoolingapp


1
Androidの面白い点は、ライフサイクルと呼ばれるものがあることです。基本フラグメントまたはダイアログフラグメントは、ライフサイクルイベントにわたって状態(およびそれらの接続)を保持できる必要があります。コールバックまたはオブザーバーはシリアル化できないため、ここで同じ問題が発生します。
GDanger
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.