从DialogFragment接收结果

Jam*_*oss 227 android dialog fragment dismiss android-fragments

我正在使用DialogFragments做很多事情:从列表中选择项目,输入文本.

将值(即字符串或列表中的项)返回给调用活动/片段的最佳方法是什么?

目前我正在制作调用活动实现DismissListener,并为DialogFragment提供对活动的引用.然后,Dialog调用OnDimissactivity中的方法,activity将从DialogFragment对象中获取结果.非常混乱,因为DialogFragment失去对活动的引用,它不能用于配置更改(方向更改).

谢谢你的帮助.

Tim*_*mmm 242

myDialogFragment.setTargetFragment(this, MY_REQUEST_CODE)在显示对话框的位置使用,然后在对话框完成后,您可以从中调用getTargetFragment().onActivityResult(getTargetRequestCode(), ...)onActivityResult()在包含的片段中实现.

这似乎是一种滥用onActivityResult(),特别是因为它根本不涉及活动.但我已经看到它被官方谷歌人推荐,甚至可能在api演示中.我认为这g/setTargetFragment()是为了增添的内容.

  • 如果目标是活动怎么办? (83认同)
  • 如果target是activity,我将使用类似"void onActivityResult2(int requestCode,int resultCode,Intent data)"的方法声明接口,并通过Activity实现它.在DialogFragment中只需getActivity并检查此接口并正确调用它. (9认同)
  • 这不是好的解决方案.保存和恢复对话框片段状态后,它将无法工作.在这种情况下,LocalBroadcastManager是最佳解决方案. (4认同)
  • @Nik这不是真的。这是最好的解决方案。保存和还原状态没有问题。如果您遇到问题,请使用错误的片段管理器。目标片段/调用者不必使用getChildFragmentManager()来显示对话框。 (3认同)
  • [`setTargetFragment`](https://developer.android.com/reference/androidx/fragment/app/Fragment#setTargetFragment(androidx.fragment.app.Fragment,%20int)) 现已弃用,但替代品 [`FragmentManager .setFragmentResultListener`](https://developer.android.com/reference/androidx/fragment/app/FragmentManager#setFragmentResultListener(java.lang.String,%20androidx.lifecycle.LifecycleOwner,%20androidx.fragment.app.FragmentResultListener)) (在[在片段之间传递数据](https://developer.android.com/training/basics/fragments/pass-data- Between)中描述)仍处于 alpha 阶段。 (3认同)
  • setTargetFragment提到请求代码用于onActivityResult,所以我想可以使用这种方法. (2认同)
  • 接口是要走的路 (2认同)

Ass*_*iel 134

正如您在这里看到的,有一种非常简单的方法可以做到这一点.

在你DialogFragment添加一个接口监听器,如:

public interface EditNameDialogListener {
    void onFinishEditDialog(String inputText);
}
Run Code Online (Sandbox Code Playgroud)

然后,添加对该侦听器的引用:

private EditNameDialogListener listener;
Run Code Online (Sandbox Code Playgroud)

这将用于"激活"侦听器方法(一个或多个),并且还检查是否父活动/片段实现此接口(见下文).

Activity/ FragmentActivity/ Fragment说:"所谓的" DialogFragment简单地实现这个接口.

DialogFragment你需要添加的所有内容中,你想要解除DialogFragment并返回结果是:

listener.onFinishEditDialog(mEditText.getText().toString());
this.dismiss();
Run Code Online (Sandbox Code Playgroud)

哪里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");
    }
}
Run Code Online (Sandbox Code Playgroud)

这种技术非常灵活,即使您还没有想要解除对话框,也可以回调结果.

  • 这适用于`````````和````FragmentActivity````'s但是如果调用者是````Fragment````? (13认同)
  • @LOG_TAG看看@Timmmm的回答.`setTargetFragment()`和`getTargetFragment()`是神奇的. (5认同)
  • 这种方法的问题在于片段在保留对象方面不是很好,因为它们是要重新创建的,例如尝试更改方向,操作系统将重新创建片段但是监听器的实例将不再可用 (4认同)
  • 如果调用者是一个"片段",那么你可以做一些事情:1.传递片段作为参考(可能不是一个好主意,因为你可能会导致内存泄漏).2.使用`FragmentManager`并调用`findFragmentById`或`findFragmentByTag`它将获得活动中存在的片段.我希望它有所帮助.祝你有美好的一天! (2认同)

Bra*_*don 48

从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.
         }
     }
}
Run Code Online (Sandbox Code Playgroud)

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");
Run Code Online (Sandbox Code Playgroud)

使用这三行,您将声明您的DialogFragment,设置一个requestCode(一旦Dialog被解除,它将调用onActivityResult(...),然后您将显示该对话框.就这么简单.

现在,在DialogFragment中,您需要直接在之前添加一行,dismiss()以便将resultCode发送回onActivityResult().

getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, getActivity().getIntent());
dismiss();
Run Code Online (Sandbox Code Playgroud)

而已.注意,resultCode定义为int resultCoderesultCode = 1;在这种情况下设置的.

就是这样,您现在可以将DialogFragment的结果发送回您的调用Activity,Fragment或FragmentActivity.

此外,看起来此信息是先前发布的,但没有给出足够的示例,所以我想我会提供更多细节.

编辑06.24.2016 我为上面的误导性代码道歉.但是你肯定无法将结果返回给作为行的活动:

dialogFrag.setTargetFragment(this, 1);
Run Code Online (Sandbox Code Playgroud)

设定目标Fragment而不是Activity.所以为了做到这一点,你需要使用工具InterfaceCommunicator.

在你的DialogFragment集合中设置一个全局变量

public InterfaceCommunicator interfaceCommunicator;
Run Code Online (Sandbox Code Playgroud)

创建一个公共函数来处理它

public interface InterfaceCommunicator {
    void sendRequestCode(int code);
}
Run Code Online (Sandbox Code Playgroud)

然后,当你准备代码发送回Activity的时候DialogFragment完成运行时,你只需在你面前添加行dismiss();DialogFragment:

interfaceCommunicator.sendRequestCode(1); // the parameter is any int code you choose.
Run Code Online (Sandbox Code Playgroud)

在您的活动中,您现在必须做两件事,第一件事是删除不再适用的那一行代码:

dialogFrag.setTargetFragment(this, 1);  
Run Code Online (Sandbox Code Playgroud)

然后实现界面,你就完成了.您可以通过implements将以下行添加到类顶部的子句中来实现:

public class MyClass Activity implements MyDialogFragment.InterfaceCommunicator
Run Code Online (Sandbox Code Playgroud)

然后@Override是活动中的功能,

@Override
public void sendRequestCode(int code) {
    // your code here
}
Run Code Online (Sandbox Code Playgroud)

您可以像使用方法一样使用此接口onActivityResult()方法.接口方法除外,DialogFragments另一个用于Fragments.

  • 嗨,你说你可以从一个Activity调用`dialogFrag.setTargetFragment(this,1)`,但是这个方法接收一个Fragment作为第一个参数,所以这个不能被渲染.我对吗 ? (6认同)
  • 如果target是Activity,则此方法将不起作用,因为受保护的访问级别无法调用其onActivityResult(来自您的DialogFragment). (4认同)
  • 那明显是错的.我在我的项目中使用了这个确切的代码.这就是我从中拉出来的地方,它运作得很好.请记住,如果您遇到此受保护的访问级别问题,则可以根据需要将任何方法和类的访问级别从受保护更改为私有或公共. (2认同)

vik*_*mar 20

好吧,为时已晚可能会回答,但这就是我所做的,以便从中获得结果DialogFragment.与@ brandon的答案非常相似.在这里,我DialogFragment从一个片段调用,只需将此代码放在您调用对话框的位置.

FragmentManager fragmentManager = getFragmentManager();
            categoryDialog.setTargetFragment(this,1);
            categoryDialog.show(fragmentManager, "dialog");
Run Code Online (Sandbox Code Playgroud)

这里categoryDialog是我的DialogFragment,我想打个电话后,这在你的实现dialogfragment将这段代码放到你在故意设置您的数据.值为resultCode1,您可以设置它或使用系统定义.

            Intent intent = new Intent();
            intent.putExtra("listdata", stringData);
            getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent);
            getDialog().dismiss();
Run Code Online (Sandbox Code Playgroud)

现在是时候回到调用片段并实现这个方法了.如果您需要with resultCoderequestCodein条件,请检查数据有效性或结果是否成功.

 @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();
    }
Run Code Online (Sandbox Code Playgroud)


小智 9

不同的方法,允许Fragment与其活动进行通信:

1)在片段中定义公共接口并为其创建变量

public OnFragmentInteractionListener mCallback;

public interface OnFragmentInteractionListener {
    void onFragmentInteraction(int id);
}
Run Code Online (Sandbox Code Playgroud)

2)将活动转换为片段中的mCallback变量

try {
    mCallback = (OnFragmentInteractionListener) getActivity();
} catch (Exception e) {
    Log.d(TAG, e.getMessage());
}
Run Code Online (Sandbox Code Playgroud)

3)在您的活动中实现监听器

public class MainActivity extends AppCompatActivity implements DFragment.OnFragmentInteractionListener  {
     //your code here
}
Run Code Online (Sandbox Code Playgroud)

4)覆盖活动中的OnFragmentInteraction

@Override
public void onFragmentInteraction(int id) {
    Log.d(TAG, "received from fragment: " + id);
}
Run Code Online (Sandbox Code Playgroud)

更多信息:https://developer.android.com/training/basics/fragments/communicating.html


ZeW*_*e15 8

我找到的一个简单方法如下:实现这是你的dialogFragment,

  CallingActivity callingActivity = (CallingActivity) getActivity();
  callingActivity.onUserSelectValue("insert selected value here");
  dismiss();
Run Code Online (Sandbox Code Playgroud)

然后在调用Dialog Fragment的活动中创建适当的函数:

 public void onUserSelectValue(String selectedValue) {

        // TODO add your implementation.
      Toast.makeText(getBaseContext(), ""+ selectedValue, Toast.LENGTH_LONG).show();
    }
Run Code Online (Sandbox Code Playgroud)

Toast表明它有效.为我工作.


小智 8

对于仍在阅读本文的任何人:setTargetFragment()已弃用。现在建议FragmentResultListener像这样使用API:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setFragmentResultListener("requestKey") { key, bundle ->
        val result = bundle.getString("resultKey")
        // Do something with the result...
    }

    ...

    // Somewhere show your dialog
    MyDialogFragment.newInstance().show(parentFragmentManager, "tag")
}
Run Code Online (Sandbox Code Playgroud)

然后在您的MyDialogFragment设置中结果:

button.setOnClickListener{
    val result = "some string"
    setFragmentResult("requestKey", bundleOf("resultKey" to result))
    dismiss()
}
Run Code Online (Sandbox Code Playgroud)

  • 随着 Fragment 库 1.3.0 (https://developer.android.com/jetpack/androidx/releases/fragment#version_130_2) 的发布,这将是“最正确”的答案。目前它只能通过 alpha 版本获得,不应在生产中使用。 (2认同)
  • `parentFragmentManager` 很重要。很容易意外发送 `childFragmentManager` ,而不会触发 setFragmentResultListener lambda (2认同)

Adi*_*ain 6

我很惊讶地看到没有人建议使用本地广播来DialogFragment进行Activity通信!我发现它比其他建议更简单,更清洁.基本上,您注册Activity要收听广播,然后从您的DialogFragment实例发送本地广播.简单.有关如何设置所有内容的分步指南,请参阅此处.

  • 我喜欢这个解决方案,这被认为是Android中的优秀或最佳实践吗? (2认同)
  • 对于Foo的爱,不要使用广播!! 它打开您的应用程序以解决安全问题.另外,我发现最糟糕的Android应用程序我必须处理滥用广播.您能想到一种更好的方法来使代码完全无法使用吗?现在我必须根除广播接收器,而不是CLEAR代码行?要明确的是有广泛使用的东西,但不是在这种情况下!永远不要在这种情况下!它只是马虎.本地与否.回调就是你所需要的. (2认同)