通过AlertDialogFragment中的Bundle传递侦听器-可能吗? [英] Passing listeners via Bundle in AlertDialogFragment - is it possible?

查看:138
本文介绍了通过AlertDialogFragment中的Bundle传递侦听器-可能吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的课:

public class AlertDialogFragment extends DialogFragment {

    private static final DialogInterface.OnClickListener DUMMY_ON_BUTTON_CLICKED_LISTENER = new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // do nothing
        }
    };

    public static final class Builder implements Parcelable {

        public static final Creator<Builder> CREATOR = new Creator<Builder>() {
            @Override
            public Builder createFromParcel(Parcel source) {
                return new Builder(source);
            }

            @Override
            public Builder[] newArray(int size) {
                return new Builder[size];
            }
        };

        private Optional<Integer> title;
        private Optional<Integer> message;
        private Optional<Integer> positiveButtonText;
        private Optional<Integer> negativeButtonText;

        public Builder() {
            title = Optional.absent();
            message = Optional.absent();
            positiveButtonText = Optional.absent();
            negativeButtonText = Optional.absent();
        }

        public Builder(Parcel in) {
            title = (Optional<Integer>) in.readSerializable();
            message = (Optional<Integer>) in.readSerializable();
            positiveButtonText = (Optional<Integer>) in.readSerializable();
            negativeButtonText = (Optional<Integer>) in.readSerializable();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            out.writeSerializable(title);
            out.writeSerializable(message);
            out.writeSerializable(positiveButtonText);
            out.writeSerializable(negativeButtonText);
        }

        @Override
        public int describeContents() {
            return 0;
        }

        public Builder withTitle(Integer title) {
            this.title = Optional.fromNullable(title);
            return this;
        }

        public Builder withMessage(Integer message) {
            this.message = Optional.fromNullable(message);
            return this;
        }

        public Builder withPositiveButton(int buttonText) {
            this.positiveButtonText = Optional.fromNullable(buttonText);
            return this;
        }

        public Builder withNegativeButton(int buttonText) {
            this.negativeButtonText = Optional.fromNullable(buttonText);
            return this;
        }

        private void set(AlertDialog.Builder dialogBuilder, final AlertDialogFragment alertDialogFragment) {
            if (title.isPresent()) {
                dialogBuilder.setTitle(title.get());
            }
            if (message.isPresent()) {
                dialogBuilder.setMessage(message.get());
            }
            if (positiveButtonText.isPresent()) {
                dialogBuilder.setPositiveButton(positiveButtonText.get(), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        alertDialogFragment.onPositiveButtonClickedListener.onClick(dialog, which);
                    }
                });
            }
            if (negativeButtonText.isPresent()) {
                dialogBuilder.setNegativeButton(negativeButtonText.get(), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        alertDialogFragment.onNegativeButtonClickedListener.onClick(dialog, which);
                    }
                });
            }
        }

        public AlertDialogFragment build() {
            return AlertDialogFragment.newInstance(this);
        }
    }


    private static final String KEY_BUILDER = "builder";

    private DialogInterface.OnClickListener onPositiveButtonClickedListener = DUMMY_ON_BUTTON_CLICKED_LISTENER;
    private DialogInterface.OnClickListener onNegativeButtonClickedListener = DUMMY_ON_BUTTON_CLICKED_LISTENER;


    private static AlertDialogFragment newInstance(Builder builder) {
        Bundle args = new Bundle();
        args.putParcelable(KEY_BUILDER, builder);
        AlertDialogFragment fragment = new AlertDialogFragment();
        fragment.setArguments(args);
        return fragment;
    }

    public void setOnPositiveButtonClickedListener(DialogInterface.OnClickListener listener) {
        this.onPositiveButtonClickedListener = listener != null ? listener : DUMMY_ON_BUTTON_CLICKED_LISTENER;
    }

    public void setOnNegativeButtonClickedListener(DialogInterface.OnClickListener listener) {
        this.onNegativeButtonClickedListener = listener != null ? listener : DUMMY_ON_BUTTON_CLICKED_LISTENER;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
        Builder builder = getArguments().getParcelable(KEY_BUILDER);
        builder.set(alertDialogBuilder, this);
        return alertDialogBuilder.create();
    }


}

现在,我必须直接在 SimpleDialogFragment 中设置按钮点击监听器,因为我无法通过 Bundle传递 listeners (参数).但我想-这样看起来就像实例化 AlertDialog :

Now I have to set on button click listeners in SimpleDialogFragment directly, because I can't pass the listeners via Bundle (args). But I want to - so it would look like instantiating an AlertDialog:

AlertDialogFragment dialogFragment = new AlertDialogFragment.Builder()
                .withTitle(R.string.no_internet_connection)
                .withMessage(messageId)
                .withPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).build();
dialogFragment.show(getSupportFragmentManager(), FRAGMENT_TAG_NO_INTERNET_CONNECTION);

但是现在我应该这样设置侦听器:

But now I should set listeners this way:

AlertDialogFragment dialogFragment = new AlertDialogFragment.Builder()
                .withTitle(R.string.no_internet_connection)
                .withMessage(messageId)
                .withPositiveButton(android.R.string.ok)
                .build();
dialogFragment.setOnPositiveButtonClickListener(new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
dialogFragment.show(getSupportFragmentManager(), FRAGMENT_TAG_NO_INTERNET_CONNECTION);

也许直接在按钮单击监听器上设置 DialogFragment 实例上,而不是通过 Bundle 参数传递它们,是不安全的,因为建议使用将参数传递给 Fragment 的方法是通过 Bundle 参数传递它们.

Perhaps setting on button click listeners directly to DialogFragment instance, rather than passing them via Bundle arguments, is not safe, because the recommended way to pass arguments to Fragment is passing them via Bundle arguments.

我知道,与 Android 中的 Fragment s通信的推荐方法是强制主机活动实现回调接口.但是通过这种方式,直到在运行时抛出 ClassCastException 之前,尚不清楚 Activity 是否应实现此接口.而且它还具有很强的依赖性-在 Activity 之外的某个地方使用它,我应该在 Activity 中实现 Callback 接口.因此,我不能在 host 活动的主机的 Fragment 的独立"中使用它: prepareAlertDialogFragment().show(getActivity().getSupportFragmentManager(),"tag");

And I know that the recommended way to communicate with Fragments in Android is to oblige host activity to implement callback interface. But this way it's not clear that Activity should implement this interface until ClassCastException will be thrown in runtime. And it also makes strong dependence - to use it somewhere outside Activity I should implement the Callback interface in Activity. So I cannot use it in Fragments "independent" of host Activities: prepareAlertDialogFragment().show(getActivity().getSupportFragmentManager(), "tag");

推荐答案

听起来,您希望有一个警报对话框,该对话框可以具有自己的侦听器,可以响应按钮按下事件(类似于OnClickListener).我实现此目标的方法是创建一个自定义DialogFragment以及一个扩展了Parcelable的侦听器.

From what it sounds like you want to have an alert dialog that can have it's own listener which can respond to button press events (kind of like OnClickListener). The way that I have achieved this is by creating a custom DialogFragment along with a listener which extends Parcelable.

ConfirmOrCancelDialogFragment.java

ConfirmOrCancelDialogFragment.java

这是您的对话框实现.除了片段的实例化方式是通过对newInstance的静态方法调用之外,它与片段的处理方式非常相似.

This is you dialog implementation. It's treated very similar to fragments except the way it's instantiated which is through a static method call to newInstance.

public class ConfirmOrCancelDialogFragment extends DialogFragment {
    TextView tvDialogHeader,
            tvDialogBody;

    Button bConfirm,
            bCancel;

    private ConfirmOrCancelDialogListener mListener;

    private String mTitle,
            mBody,
            mConfirmButton,
            mCancelButton;

    public ConfirmOrCancelDialogFragment() {
    }

    public static ConfirmOrCancelDialogFragment newInstance(String title, String body, ConfirmOrCancelDialogListener listener) {
        ConfirmOrCancelDialogFragment fragment = new ConfirmOrCancelDialogFragment();
        Bundle args = new Bundle();
        args.putString("title", title);
        args.putString("body", body);
        args.putParcelable("listener", listener);
        fragment.setArguments(args);
        return fragment;
    }

    public static ConfirmOrCancelDialogFragment newInstance(String title, String body, String confirmButton, String cancelButton, ConfirmOrCancelDialogListener listener) {
        ConfirmOrCancelDialogFragment fragment = new ConfirmOrCancelDialogFragment();
        Bundle args = new Bundle();
        args.putString("title", title);
        args.putString("body", body);
        args.putString("confirmButton", confirmButton);
        args.putString("cancelButton", cancelButton);
        args.putParcelable("listener", listener);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.dialog_confirm_or_cancel, container);

        /* Initial Dialog Setup */
        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); // we are using a textview for the title
        mListener = getArguments().getParcelable("listener");

        /* Link UI */
        tvDialogHeader = (TextView) view.findViewById(R.id.tvDialogHeader);
        tvDialogBody = (TextView) view.findViewById(R.id.tvDialogBody);
        bConfirm = (Button) view.findViewById(R.id.bConfirm);
        bCancel = (Button) view.findViewById(R.id.bCancel);

        /* Setup UI */
        mTitle = getArguments().getString("title", "");
        mBody = getArguments().getString("body", "");
        mConfirmButton = getArguments().getString("confirmButton", getResources().getString(R.string.yes_delete));
        mCancelButton = getArguments().getString("cancelButton", getResources().getString(R.string.no_do_not_delete));

        tvDialogHeader.setText(mTitle);
        tvDialogBody.setText(mBody);
        bConfirm.setText(mConfirmButton);
        bCancel.setText(mCancelButton);

        bConfirm.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.onConfirmButtonPressed();
                dismiss();
            }
        });

        bCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.onCancelButtonPressed();
                dismiss();
            }
        });

        return view;
    }
}

ConfirmOrCancelDialogListener.java

ConfirmOrCancelDialogListener.java

这是您的侦听器实现,您可以随时向其添加更多内容,但只需确保它扩展了Parcelable,以便可以将其通过ConfirmOrCancelDialogFragment.java中的newInstance方法中的捆绑包进行传递

This is your listener implementation, you could always add more to this, but just make sure it extends Parcelable so it can be passed through the bundle in the newInstance method found in ConfirmOrCancelDialogFragment.java

public interface ConfirmOrCancelDialogListener extends Parcelable {
    void onConfirmButtonPressed();

    void onCancelButtonPressed();
}

使用示例:

在这里,事情变得比我想要的更混乱.由于您的侦听器正在扩展Parcelable,因此您还必须重写那些方法,这些方法是describeContents和writeToParcel.幸运的是,它们基本上可以是空白,并且一切正常.

This is where things get a little messier than I would like. Since your listener is extending Parcelable you also have to override those methods as well which are describeContents and writeToParcel. Luckily they can be mostly blank and everything still works fine.

FragmentManager fm = getActivity().getSupportFragmentManager();
ConfirmOrCancelDialogFragment confirmOrCancelDialogFragment = ConfirmOrCancelDialogFragment.newInstance
    (getString(R.string.header), getString(R.string.body),
                        new ConfirmOrCancelDialogListener() {
                            @Override
                            public void onConfirmButtonPressed() {

                            }

                            public void onCancelButtonPressed() {
                            }

                            @Override
                            public int describeContents() {
                                return 0;
                            }

                            @Override
                            public void writeToParcel(Parcel dest, int flags) {
                            }
                        }
                );
confirmOrCancelDialogFragment.show(fm, "fragment_delete_confirmation");

这不能完全回答您将它们通过AlertDialogFragment传递的问题,但是我认为如果这个问题长时间没有得到解答,那么值得举一个例子,说明如何使用自定义对话框完成任务,这似乎可以为您提供帮助无论如何,还是要更多地控制样式和功能.

This doesn't completely answer your question of passing them in through an AlertDialogFragment, but I figure if this question has gone unanswered this long it's worth giving an example of how to accomplish task with a custom Dialog, which seems to give you a little more control over the style and functionality anyway.

这篇关于通过AlertDialogFragment中的Bundle传递侦听器-可能吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆