在AlertDialogFragment中通过Bundle传递侦听器——这是可能的吗?

时间:2023-01-27 19:09:29

I have a simple class:

我有一个简单的类:

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();
    }


}

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:

现在我必须在SimpleDialogFragment中直接设置按钮单击监听器,因为我无法通过Bundle (args)传递监听器。但是我想要-看起来像是实例化一个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);

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.

也许设置按钮单击监听器直接到DialogFragment实例(而不是通过Bundle参数传递它们)是不安全的,因为推荐的传递参数到Fragment的方式是通过Bundle参数传递。

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");

我知道在Android中与片段通信的推荐方式是迫使主机活动实现回调接口。但是这样,在ClassCastException在运行时被抛出之前,不清楚活动是否应该实现这个接口。它还具有很强的依赖性——要在活动之外使用它,我应该在活动中实现回调接口。因此,我不能将其用于“独立”的主机活动的片段中:prepareAlertDialogFragment().show(getActivity().getSupportFragmentManager(),“tag”);

1 个解决方案

#1


6  

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.

听起来你想要一个警报对话框,它有自己的监听器,可以响应按钮按下的事件(有点像OnClickListener)。我实现这一点的方法是创建一个自定义对话框片段,并创建一个扩展Parcelable的侦听器。

ConfirmOrCancelDialogFragment.java

ConfirmOrCancelDialogFragment.java

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.

这是对话框的实现。它的处理方式与片段非常相似,除了通过对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

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

这是侦听器实现,您可以向它添加更多的内容,但是要确保它扩展了Parcelable,以便可以在confirmorcanceldialogment.java中找到的newInstance方法中的bundle中传递它

public interface ConfirmOrCancelDialogListener extends Parcelable {
    void onConfirmButtonPressed();

    void onCancelButtonPressed();
}

Use Example:

使用的例子:

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.

这就是事情变得比我想要的更混乱的地方。由于侦听器正在扩展可分割性,您还必须重写这些方法,它们是可描述的和writeToParcel。幸运的是,它们大部分都是空白的,而且一切都还正常。

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");

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,但是我认为如果这个问题已经回答这么长时间是值得给一个例子如何完成任务的一个自定义对话框中,这似乎给你多一点的控制风格和功能。

#1


6  

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.

听起来你想要一个警报对话框,它有自己的监听器,可以响应按钮按下的事件(有点像OnClickListener)。我实现这一点的方法是创建一个自定义对话框片段,并创建一个扩展Parcelable的侦听器。

ConfirmOrCancelDialogFragment.java

ConfirmOrCancelDialogFragment.java

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.

这是对话框的实现。它的处理方式与片段非常相似,除了通过对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

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

这是侦听器实现,您可以向它添加更多的内容,但是要确保它扩展了Parcelable,以便可以在confirmorcanceldialogment.java中找到的newInstance方法中的bundle中传递它

public interface ConfirmOrCancelDialogListener extends Parcelable {
    void onConfirmButtonPressed();

    void onCancelButtonPressed();
}

Use Example:

使用的例子:

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.

这就是事情变得比我想要的更混乱的地方。由于侦听器正在扩展可分割性,您还必须重写这些方法,它们是可描述的和writeToParcel。幸运的是,它们大部分都是空白的,而且一切都还正常。

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");

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,但是我认为如果这个问题已经回答这么长时间是值得给一个例子如何完成任务的一个自定义对话框中,这似乎给你多一点的控制风格和功能。