【问题标题】:Android: What is the proper way of connecting dialog buttons with an activity?Android:将对话框按钮与活动连接的正确方法是什么?
【发布时间】:2013-11-02 04:27:35
【问题描述】:

这是我想做的:

1) 在Activity 中显示一个对话框。我为此使用DialogFragmentFragmentManager,通过调用:

dialogFragment.show(fragmentManager, "edit_task_list");

2) 在Dialog 内部,我有一个自定义Button 的布局。我想在单击按钮时执行一些操作,然后关闭对话框。

我应该如何连接所有东西?我看到两个选项:

1) Button 中的onclick 属性和Actvity 中的方法。那是我最初的计划,但我不知道如何从Activity 获得Dialog 来驳回它。即使这不是正确的方法,又怎么能这样做呢?我想了解它是如何工作的。

2) 在DialogFragment 中创建Dialog 时,在按钮上设置点击侦听器。这将需要我将一些上下文从Activity 传递给DialogFragment,所以我想避免它(并保持DialogFragment 尽可能简单)。

我应该选择哪些选项?

【问题讨论】:

  • 我猜你应该使用接口并且活动必须实现它的方法。您可以在其中传递所有有用的对象,甚至是对话框对象。

标签: android dialog


【解决方案1】:

数字 2 不要求您传递任何上下文(而且您不应该)。您定义一个接口,该接口可以充当片段和活动之间的契约,并使您的活动实现它。

在您的对话框和 button.onClick() 中,您可以执行以下操作(未经测试的代码):

if ( getActivity() != null 
      && !getActivity().finishing() 
      && getActivity() instanceOf YourInterface) {
   ((YourInterface)getActivity()).onSomeNiceMethod();
   dismiss(); // close the dialog (if this is what you want).
}

界面如下:

public interface YourInterface {
     void onSomeNiceMethod();
}

还有你的活动……

public class YourActivity implements YourInterface {
     void onSomeNiceMethod() {
         // Hey! The Button In The Dialog Has Been Pressed!
     }
}

【讨论】:

    【解决方案2】:

    所有 Activity 和 Fragment 类都有一个内置的回调方法供您在启动另一个 Activity、Fragment、Dialog 或 DialogFragment 时使用。

     void onActivityResult(int requestCode, int resultCode, Intent data)
    

    既然要从 Activity 启动 Dialog,使用 Dialog 类比使用 DialogFragment 类好。后者更适合从 Fragment 启动对话,因为它有两种与 Fragment 通信的方法 (get/set TargetFragment())

    Dialog 类具有getOwnerActivity() 方法。这是您在使用其构造函数之一创建 Dialog 时使用的 Activity。

    您在 Dialog 类的按钮上设置了 onClickListener。将结果传递回 Activity:

    getOwnerActivity().onActivityResult(intIdentifyingme, Activity.RESULT_OK,
                        intent);
    dismiss();  // close the dialog
    

    您将要发送的其他信息放入 Intent。

    【讨论】:

      【解决方案3】:

      1) Button 中的onclick 属性和Actvity 中的方法。 那是我最初的计划,但我不知道如何从 取消它的活动。即使这不是正确的方式,又怎么能 这能做到吗?我想了解它是如何工作的。

      基本上,您的 Activity 必须记住/知道当前哪个对话框处于活动状态,例如 curDialog=dialogFragment;,然后在处理按钮 onclick 操作时,您将知道要关闭哪个对话框。但这确实不是一个好主意,因为基本上 Button View 会从您的 DialogFragment “泄漏”到您的 Activity,这会破坏对象封装。

      2) 在创建对话框时在按钮上设置点击侦听器 对话片段。这将需要我从 DialogFragment 的 Activity,所以我想避免它(并保持 DialogFragment 尽可能简单)。

      正如前面提到的答案,您不需要将任何 Context 传递给它,特别是因为您可以通过调用 getActivity() 来获取 Activity。

      解决方案取决于此对话框是否会被多个活动使用:

      1. 由单个 Activity 使用:@Martin 的解决方案可以正常工作
      2. 由多个 Activity 使用:可以使用抽象,这样只有用户的决定会传递给侦听器。这是我针对相同问题提出的(修改后的)解决方案:

        public class BaseDialogFragment extends DialogFragment {
            protected TextView dialogEn;
            protected Button dialogYes;
            private Button dialogNo;
            protected OnSelectListener listener;
        
        public interface OnSelectListener {
            public void onSelect(int type, boolean yes);
        }
        
        public void setOnSelectListener(OnSelectListener listener) {
            this.listener = listener;
        }
        
        public BaseDialogFragment() {
            super();
        }
        
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.dialog_confirm, container, false);
        dialogYes = (Button) v.findViewById(R.id.yes);
        dialogNo = (Button) v.findViewById(R.id.no);
        
        dialogEn = (TextView) view.findViewById(R.id.dialog_en);
        dialogEn.setText(getArguments().getString("text_en"));
        dialogYes.setOnClickListener(this);
        dialogNo.setOnClickListener(this);
        return v;
        }
        
        public void onClick(View v) {
            if (listener != null) {
                listener.onSelect(getArguments().getInt("type"),
                        v == dialogYes ? true : false);
            }
            getDialog().dismiss();
        }
        }
        

      要使用它,需要提供一些额外的信息:

          Bundle bundle = new Bundle();
          bundle.putInt("type", type); //type: an unique integer value that helps differentiate result from different dialogs
          bundle.putString("text_en", en); //en: String to be displayed
          dialog.setArguments(bundle);
          dialog.setOnSelectListener(this);
      

      因此,如果上面的 type 值设置为 115,则单击 dialogYes 按钮将触发 public void onSelect(int type, boolean yes) 方法,并使用 115true 作为第一个和第二个参数来调用。

      【讨论】:

        【解决方案4】:

        应该避免关于 xml 中的 onClick 属性的第一点。因为如果您尊重屏幕旋转或具有多个对话框的设置等事件,那么以这种方式处理对话框可能会非常痛苦。这在大多数情况下会导致泄漏的窗口错误,并且需要不必要的代码开销来避免这种情况。因为您必须跟踪实际显示的对话框。 为了能够以这种方式关闭对话框,您可以使用您在调用时设置的标签dialogFragment.show(fragmentManager, "edit_task_list");

        DialogFragment frag = (DialogFragment)getFragmentManager().findFragmentByTag("edit_task_list");
        if(frag != null)
            frag.dismiss();
        

        正确的解决方案是使用接口作为DialogFragment和Activity之间通信的回调。这使 Dialog 模块化和代码简单。这是来自docs 的示例。为此,您不需要上下文。您只需将接口传递给onAttach() 回调中的对话框。它有一个 Activity 的引用作为参数,它调用了那个 Dialog。

        // Example interface for the communication
        public interface OnArticleSelectedListener {
            public void onButtonClicked(/*any Parameters*/);
        }
        
        public static class FragmentA extends DialogFragment {
            OnArticleSelectedListener mListener;
            ...
            @Override
            public void onAttach(Activity activity) {
                super.onAttach(activity);
                try {
                    mListener = (OnArticleSelectedListener) activity; // get the interface of the Activity
                } catch (ClassCastException e) {
                    throw new ClassCastException(activity.toString() 
                            + " must implement OnArticleSelectedListener");
                }
            }
            ...
        }
        

        在对话框中处理按钮单击并在其中调用dismiss(),对话框可以自行关闭。看看这个question为什么要使用dismiss()而不是getDialog().dismiss()。

        yourButton.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v){
                if(mListener != null) // check if the listener is still valid
                    mListener.onButtonClicked(...); // calls the Activity implementation of this callback
                dismiss(); // dismiss the Dialog
            }
        });
        

        在对话框的onPause() 中将接口的引用设置为null。这样您就可以确保只有在显示对话框时才会使用回调。

        您的 Activity 看起来像这样以便能够处理回调:

        public class MyActivity extends Activity implements OnArticleSelectedListener{
            ...
            @Override
            public void onButtonClicked(...){
                // your implementation here
            }
        }
        

        我不知道您的整体设置,但如果您要使用 AlertDialog,则单击按钮会在方法返回时自动关闭对话框。

        【讨论】:

          猜你喜欢
          • 2018-11-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-08
          • 2011-06-22
          相关资源
          最近更新 更多