Java 通过AlertDialogFragment中的Bundle传递侦听器-可能吗?

Java 通过AlertDialogFragment中的Bundle传递侦听器-可能吗?,java,android,Java,Android,我有一个简单的课程: public class AlertDialogFragment extends DialogFragment { private static final DialogInterface.OnClickListener DUMMY_ON_BUTTON_CLICKED_LISTENER = new DialogInterface.OnClickListener() { @Override public void onClick(Di

我有一个简单的课程:

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


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

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);
AlertDialogFragment.newInstance(
            getString(R.string.example_parameter),
            object : AlertDialogFragment.Companion.AlertDialogListener {
                override fun primaryActionClicked() {
                    // DO SOMETHING ABOUT THE ACTION
                }
            }
        ).show(childFragmentManager, AlertDialogFragment::class.java.name)
也许将按钮单击侦听器直接设置为
DialogFragment
实例而不是通过
Bundle
参数传递它们是不安全的,因为向
Fragment
传递参数的推荐方法是通过
Bundle
参数传递它们


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

听起来,您希望有一个警报对话框,它可以有自己的侦听器,可以响应按钮按下事件(有点像OnClickListener)。我实现这一点的方法是创建一个自定义DialogFragment以及一个扩展Parcelable的侦听器

confirmonceldialogfragment.java

public interface ConfirmOrCancelDialogListener extends Parcelable {
    void onConfirmButtonPressed();

    void onCancelButtonPressed();
}
这是您的对话框实现。除了通过对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;
    }
}
confirmonceldialoglistener.java

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

public interface ConfirmOrCancelDialogListener extends Parcelable {
    void onConfirmButtonPressed();

    void onCancelButtonPressed();
}
使用示例:

这就是事情变得比我想的更混乱的地方。由于您的侦听器正在扩展Parcelable,因此您还必须重写这些方法,即DescripteBontents和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");

这并不能完全回答您通过AlertDialogFragment传递它们的问题,但我认为如果这个问题这么长时间都没有得到回答,那么就值得给出一个如何使用自定义对话框完成任务的示例,这似乎让您对样式和功能有了更多的控制。

如果您需要Kotlin版本,只需少量升级,请参阅:

class AlertDialogFragment : DialogFragment() {
    companion object {
        internal fun newInstance(
            exampleParameter: String,
            listener: AlertDialogListener? = null
        ) = AlertDialogFragment().apply {
            this.arguments = Bundle().apply {
                this.putString(EXAMPLE_PARAMETER, exampleParameter)
                this.putParcelable(ALERT_LISTENER, listener)
            }
        }

        interface AlertDialogListener: Parcelable {
            fun primaryActionClicked()
            fun secondaryActionClicked() { /* nop */ }
            override fun describeContents(): Int = 0
            override fun writeToParcel(dest: Parcel, flags: Int) { /* nop */ }
        }

        const val EXAMPLE_PARAMETER = "example_parameter"
        const val ALERT_LISTENER = "alert_listener"
    }

    private var listener: AlertDialogListener? = null

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return inflater.inflate(R.layout.dialog_alert, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        initListeners()
        initExampleParameter()
    }

    private fun initListeners() {
        val listener = arguments!!.getParcelable<AlertDialogListener>(ALERT_LISTENER)
        if (listener != null) {
            this.listener = listener
        }
    }

    private fun initExampleParameter() {
        example_view.text = arguments!!.getString(EXAMPLE_PARAMETER)!!
        example_view.setOnClickListener {
            listener?.primaryActionClicked()
            dismiss()
        }
    }
}

您可能还希望忽略listener参数,以防您只需要将发生的事情通知用户。快乐编码

你需要一个包裹。创建者吗?不,你不应该需要一个包裹。创建者。上面的代码应该已准备好进行复制。请注意,此方法可能会导致问题。在设备上的开发人员选项中,打开“不保留活动”设置,确保返回使用此方法的片段时不会崩溃。通常,会引发异常,因为侦听器已不在内存中,并且没有创建者重新实例化它。任何可以序列化(可序列化或可打包)的对象都不应包含对UI对象的引用。此方法不鼓励使用,会导致错误。