私はDialogFragmentsを使用しています。リストから項目を選択し、テキストを入力します。
呼び出しアクティビティ/フラグメントに値(つまり、文字列またはリストのアイテム)を返す最良の方法は何ですか?
現在、呼び出しアクティビティにDismissListener
を実装させ、DialogFragmentにアクティビティへの参照を与えています。次に、DialogはアクティビティでOnDimiss
メソッドを呼び出し、アクティビティはDialogFragmentオブジェクトから結果を取得します。 DialogFragmentはアクティビティへの参照を失うため、非常に乱雑であり、構成の変更(方向の変更)では機能しません。
助けてくれてありがとう。
ダイアログを表示する場所からmyDialogFragment.setTargetFragment(this, MY_REQUEST_CODE)
を使用し、ダイアログが終了したら、そこからgetTargetFragment().onActivityResult(getTargetRequestCode(), ...)
を呼び出して、含むフラグメントにonActivityResult()
を実装できます。
特にアクティビティをまったく伴わないため、onActivityResult()
の不正使用のようです。しかし、私は公式のグーグルの人々、そしておそらくAPIデモでも推奨されているのを見ました。 g/setTargetFragment()
が追加された理由だと思います。
here を見るとわかるように、非常に簡単な方法があります。
DialogFragment
に次のようなインターフェイスリスナーを追加します。
public interface EditNameDialogListener {
void onFinishEditDialog(String inputText);
}
次に、そのリスナーへの参照を追加します。
private EditNameDialogListener listener;
これは、リスナーメソッドを「アクティブ化」するために使用され、また、親Activity/Fragmentがこのインターフェイスを実装しているかどうかを確認するために使用されます(以下を参照)。
Activity
を「呼び出した」FragmentActivity
/Fragment
/DialogFragment
で、このインターフェイスを実装するだけです。
DialogFragment
で、DialogFragment
を閉じて結果を返す場所に追加する必要があるのは次のとおりです。
listener.onFinishEditDialog(mEditText.getText().toString());
this.dismiss();
mEditText.getText().toString()
は、呼び出し元のActivity
に返されるものです。
他の何かを返したい場合は、リスナーが取る引数を変更するだけです。
最後に、インターフェイスが実際に親アクティビティ/フラグメントによって実装されたかどうかを確認する必要があります。
@Override
public void onAttach(Context context) {
super.onAttach(context);
// Verify that the Host activity implements the callback interface
try {
// Instantiate the EditNameDialogListener so we can send events to the Host
listener = (EditNameDialogListener) context;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(context.toString()
+ " must implement EditNameDialogListener");
}
}
この手法は非常に柔軟であり、たとえダイアログをまだ閉じたくない場合でも、結果でコールバックできます。
DialogFragmentから結果を受け取るはるかに簡単な方法があります。
まず、Activity、Fragment、またはFragmentActivityで、次の情報を追加する必要があります。
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Stuff to do, dependent on requestCode and resultCode
if(requestCode == 1) { // 1 is an arbitrary number, can be any int
// This is the return result of your DialogFragment
if(resultCode == 1) { // 1 is an arbitrary number, can be any int
// Now do what you need to do after the dialog dismisses.
}
}
}
requestCode
は基本的に、呼び出したDialogFragmentのintラベルです。これがどのように機能するかをすぐに示します。 resultCodeは、DialogFragmentから送り返され、現在待機中のActivity、Fragment、またはFragmentActivityに何が起こったかを伝えるコードです。
次に進むコードは、DialogFragmentの呼び出しです。例は次のとおりです。
DialogFragment dialogFrag = new MyDialogFragment();
// This is the requestCode that you are sending.
dialogFrag.setTargetFragment(this, 1);
// This is the tag, "dialog" being sent.
dialogFrag.show(getFragmentManager(), "dialog");
これらの3行を使用して、DialogFragmentを宣言し、requestCode(onActivityResult(...)を呼び出すとダイアログが閉じられ、ダイアログが表示されます)を設定します。それは簡単です。
ここで、DialogFragmentでdismiss()
の直前に1行追加するだけで、onActivityResult()にresultCodeを送り返すことができます。
getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, getActivity().getIntent());
dismiss();
それでおしまい。なお、resultCodeはint resultCode
として定義されており、この場合はresultCode = 1;
に設定しています。
これで、DialogFragmentの結果を呼び出し側のActivity、Fragment、またはFragmentActivityに返送できるようになりました。
また、この情報は以前に投稿されたように見えますが、十分な例が示されていなかったため、詳細を提供すると思いました。
EDIT 06.24.2016上記の誤解を招くコードをおaび申し上げます。しかし、次のように見えるアクティビティに結果を戻すことはできません。
dialogFrag.setTargetFragment(this, 1);
Fragment
ではなく、ターゲットActivity
を設定します。したがって、これを行うには、InterfaceCommunicator
の実装を使用する必要があります。
DialogFragment
にグローバル変数を設定します
public InterfaceCommunicator interfaceCommunicator;
パブリック関数を作成して処理します
public interface InterfaceCommunicator {
void sendRequestCode(int code);
}
次に、Activity
の実行が完了したときにコードをDialogFragment
に送り返す準備ができたら、単にdismiss();
をDialogFragment
の前に追加します。
interfaceCommunicator.sendRequestCode(1); // the parameter is any int code you choose.
アクティビティでは、次の2つのことを行う必要があります。1つ目は、適用されなくなった1行のコードを削除することです。
dialogFrag.setTargetFragment(this, 1);
その後、インターフェースを実装すれば完了です。クラスの最上部にあるimplements
句に次の行を追加することにより、これを行うことができます。
public class MyClass Activity implements MyDialogFragment.InterfaceCommunicator
そして、@Override
アクティビティ内の関数、
@Override
public void sendRequestCode(int code) {
// your code here
}
このインターフェイスメソッドは、onActivityResult()
メソッドと同じように使用します。インターフェイスメソッドがDialogFragments
用であり、もう1つがFragments
用である場合を除きます。
遅すぎるかもしれませんが、ここでDialogFragment
から結果を取得するために行ったことを示します。 @brandonの答えに非常に似ています。ここでは、フラグメントからDialogFragment
を呼び出しています。ダイアログを呼び出す場所にこのコードを配置してください。
FragmentManager fragmentManager = getFragmentManager();
categoryDialog.setTargetFragment(this,1);
categoryDialog.show(fragmentManager, "dialog");
ここでcategoryDialog
は呼び出したいDialogFragment
であり、この後dialogfragment
の実装でこのコードをデータを意図的に設定する場所に配置します。 resultCode
の値は1です。設定するか、システム定義を使用できます。
Intent intent = new Intent();
intent.putExtra("listdata", stringData);
getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent);
getDialog().dismiss();
ここで、呼び出し元のフラグメントに戻り、このメソッドを実装します。 if条件でresultCode
およびrequestCode
を使用する場合は、データの有効性または結果の成功を確認してください。
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//do what ever you want here, and get the result from intent like below
String myData = data.getStringExtra("listdata");
Toast.makeText(getActivity(),data.getStringExtra("listdata"),Toast.LENGTH_SHORT).show();
}
FragmentがそのActivityまで通信できるようにする別のアプローチ:
1)フラグメントにパブリックインターフェイスを定義し、そのための変数を作成します
public OnFragmentInteractionListener mCallback;
public interface OnFragmentInteractionListener {
void onFragmentInteraction(int id);
}
2)アクティビティをフラグメントのmCallback変数にキャストします
try {
mCallback = (OnFragmentInteractionListener) getActivity();
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
3)アクティビティにリスナーを実装します
public class MainActivity extends AppCompatActivity implements DFragment.OnFragmentInteractionListener {
//your code here
}
4)アクティビティのOnFragmentInteractionをオーバーライドします
@Override
public void onFragmentInteraction(int id) {
Log.d(TAG, "received from fragment: " + id);
}
詳細情報: https://developer.Android.com/training/basics/fragments/communicating.html
私が見つけた簡単な方法の1つは次のとおりです。これを実装するのは、dialogFragmentです。
CallingActivity callingActivity = (CallingActivity) getActivity();
callingActivity.onUserSelectValue("insert selected value here");
dismiss();
そして、Dialog Fragmentを呼び出したアクティビティで適切な関数を作成します:
public void onUserSelectValue(String selectedValue) {
// TODO add your implementation.
Toast.makeText(getBaseContext(), ""+ selectedValue, Toast.LENGTH_LONG).show();
}
トーストは、それが機能することを示すことです。私のために働いた。
DialogFragment
からActivity
への通信にローカルブロードキャストを使用することを誰も提案していないことに非常に驚いています!私はそれが他の提案よりもはるかにシンプルでクリーンであることがわかりました。基本的に、Activity
を登録してブロードキャストをリッスンし、DialogFragment
インスタンスからローカルブロードキャストを送信します。シンプル。すべての設定方法に関するステップバイステップガイドについては、 here を参照してください。
または、次のようにViewModelを共有します。
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// Update the UI.
});
}
}
https://developer.Android.com/topic/libraries/architecture/viewmodel#sharing_data_between_fragments
私の場合、targetFragmentに引数を渡す必要がありました。しかし、「Fragment already active」という例外が発生しました。だから、parentFragmentが実装するDialogFragmentでInterfaceを宣言しました。 parentFragmentがDialogFragmentを開始すると、自身をTargetFragmentとして設定します。次に、DialogFragmentで呼び出しました
((Interface)getTargetFragment()).onSomething(selectedListPosition);
引数を送信し、2番目のフラグメントから結果を受信する場合、Fragment.setArgumentsを使用してこのタスクを実行できます。
static class FirstFragment extends Fragment {
final Handler mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 101: // receive the result from SecondFragment
Object result = msg.obj;
// do something according to the result
break;
}
};
};
void onStartSecondFragments() {
Message msg = Message.obtain(mUIHandler, 101, 102, 103, new Object()); // replace Object with a Parcelable if you want to across Save/Restore
// instance
putParcelable(new SecondFragment(), msg).show(getFragmentManager().beginTransaction(), null);
}
}
static class SecondFragment extends DialogFragment {
Message mMsg; // arguments from the caller/FirstFragment
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
mMsg = getParcelable(this);
}
void onClickOK() {
mMsg.obj = new Object(); // send the result to the caller/FirstFragment
mMsg.sendToTarget();
}
}
static <T extends Fragment> T putParcelable(T f, Parcelable arg) {
if (f.getArguments() == null) {
f.setArguments(new Bundle());
}
f.getArguments().putParcelable("extra_args", arg);
return f;
}
static <T extends Parcelable> T getParcelable(Fragment f) {
return f.getArguments().getParcelable("extra_args");
}
コトリンで
// My DialogFragment
クラスFiltroDialogFragment:DialogFragment()、View.OnClickListener {
var listener: InterfaceCommunicator? = null
override fun onAttach(context: Context?) {
super.onAttach(context)
listener = context as InterfaceCommunicator
}
interface InterfaceCommunicator {
fun sendRequest(value: String)
}
override fun onClick(v: View) {
when (v.id) {
R.id.buttonOk -> {
//You can change value
listener?.sendRequest('send data')
dismiss()
}
}
}
}
//私の活動
クラスMyActivity:AppCompatActivity()、FiltroDialogFragment.InterfaceCommunicator {
override fun sendRequest(value: String) {
// :)
Toast.makeText(this, value, Toast.LENGTH_LONG).show()
}
}
私はそれが役立つことを願っています、あなたが改善できるならそれを編集してください。私の英語はあまり上手ではありません