如何在 android 的自定义对话框中设置自定义侦听器?

How to set up a custom listener in a custom dialog for android?

我目前在设置自定义侦听器时遇到问题。我只想将一个字符串从我的对话框传递到我的片段(我在其中设置对话框)。我试图按照本教程进行操作:https://www.youtube.com/watch?v=ARezg1D9Zd0

在 10:38 分钟,他设置了侦听器。 唯一的问题是,在此,他使用 DialogFragment,但我正在扩展对话框,但我不知道如何将上下文附加到侦听器。

我尝试在 onAttachedToWindow() 和对话框构造函数中进行设置,但它崩溃了。

我应该怎么做?

如果有人能解释一下两者之间的区别,我将不胜感激:

onAttachedToWindow() 与 onAttach(Context 上下文)。

谢谢!

我的自定义对话框:

public class NewListDialog extends Dialog implements View.OnClickListener {

    private Activity c;
    private TextInputLayout textInputLayout;
    private TextInputEditText editText;
    private LinearLayout dialog_root_view;
    private Animation fade_out;
    private String list_name;

    private NewListDialogListener listener;

    NewListDialog(Activity a) {
        super(a);
        this.c = a;

        //ANOTHER ATTEMPT TO ATTACH CONTEXT TO LISTENER
        //listener = (NewListDialogListener) a.getApplicationContext();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.new_list_dialog);

        MaterialButton cancel = findViewById(R.id.dialog_new_list_cancel_button);
        MaterialButton create = findViewById(R.id.dialog_new_list_create_button);
        textInputLayout = findViewById(R.id.dialog_text_input_layout);
        editText = findViewById(R.id.dialog_edit_text);
        dialog_root_view = findViewById(R.id.dialog_root);
        fade_out =  AnimationUtils.loadAnimation(c, R.anim.fade_out_dialog);

        editText.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View view, int i, KeyEvent keyEvent) {
                if (isTextValid(editText.getText())) {
                    textInputLayout.setError(null);
                    return true;
                }
                return false;
            }
        });


        cancel.setOnClickListener(this);
        create.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            //Cancel Button
            case R.id.dialog_new_list_cancel_button:
                dialog_root_view.startAnimation(fade_out);
                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        dismiss();
                    }
                }, 200);
                break;

            //Create Button
            case R.id.dialog_new_list_create_button:
                if (!isTextValid(editText.getText())) {
                    textInputLayout.setError(c.getString(R.string.dialog_error));
                } else {
                    textInputLayout.setError(null);

                    //record input string
                    list_name = editText.getText().toString();

                    //send information to parent activity
                    //What to put here?
                    listener.createListName(list_name);
                    dismiss();
                }
                break;

            default:
                break;
        }
    }

    private boolean isTextValid(@Nullable Editable text) {
        return text != null && text.length() > 0;
    }

    //ATTEMPT TO ATTACH CONTEXT TO LISTENER
    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();

        try {
            listener = (NewListDialogListener) c.getBaseContext();
        } catch (ClassCastException e) {
            throw new ClassCastException(c.getBaseContext().toString() + "must implement ExampleDialogListener");
        }
    }

    public interface NewListDialogListener {
        void createListName(String listname);
    }
}

在android中FragmentsActivity有生命周期。 Fragments 托管在 Activity 内,并通过 onattach 方法获取主机 activity 的上下文。

另一方面,Dialog是从Object(上帝class)扩展而来的,没有任何生命周期,应该被视为一个对象。

如果您的 activity 正在实施 NewListDialogListener 那么您可以

listener = (NewListDialogListener) a;

onAttachedToWindow : 表示对话框将很快在屏幕上绘制

getApplicationContext() 将为您提供应用程序的上下文对象(每个应用程序一个),这肯定与您的侦听器无关,因此不会工作

参考:

Android DialogFragment vs Dialog

getContext()、getApplicationContext()、getBaseContext() 和“this”之间的区别

如果您定义了自定义对话框,那么您可以声明一个方法以允许其他组件调用它或侦听此对话框上的事件。将此方法添加到您的自定义对话框中。

public void setNewListDialogListener(NewListDialogListener listener){
    this.listener = listener;
}

NewListDialog.java

public class NewListDialog extends Dialog implements View.OnClickListener {

    private Activity c;
    private TextInputLayout textInputLayout;
    private TextInputEditText editText;
    private LinearLayout dialog_root_view;
    private Animation fade_out;
    private String list_name;

    private NewListDialogListener listener;

    NewListDialog(Activity a) {
        super(a);
        this.c = a;
    }

    public void setNewListDialogListener(NewListDialogListener listener) {
        this.listener = listener;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.new_list_dialog);

        MaterialButton cancel = findViewById(R.id.dialog_new_list_cancel_button);
        MaterialButton create = findViewById(R.id.dialog_new_list_create_button);
        textInputLayout = findViewById(R.id.dialog_text_input_layout);
        editText = findViewById(R.id.dialog_edit_text);
        dialog_root_view = findViewById(R.id.dialog_root);
        fade_out =  AnimationUtils.loadAnimation(c, R.anim.fade_out_dialog);

        editText.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View view, int i, KeyEvent keyEvent) {
                if (isTextValid(editText.getText())) {
                    textInputLayout.setError(null);
                    return true;
                }
                return false;
            }
        });


        cancel.setOnClickListener(this);
        create.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            //Cancel Button
            case R.id.dialog_new_list_cancel_button:
                dialog_root_view.startAnimation(fade_out);
                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        dismiss();
                    }
                }, 200);
                break;

            //Create Button
            case R.id.dialog_new_list_create_button:
                if (!isTextValid(editText.getText())) {
                    textInputLayout.setError(c.getString(R.string.dialog_error));
                } else {
                    textInputLayout.setError(null);

                    //record input string
                    list_name = editText.getText().toString();

                    //send information to parent activity
                    //What to put here?
                    if (listener != null) {
                        listener.createListName(list_name);
                    }
                    dismiss();
                }
                break;

            default:
                break;
        }
    }

    private boolean isTextValid(@Nullable Editable text) {
        return text != null && text.length() > 0;
    }

    public interface NewListDialogListener {
        void createListName(String listname);
    }
}

在其他组件中,例如必须实现 NewListDialogListener 的 activity。

NewListDialog dialog = new NewListDialog(this);
dialog.setNewListDialogListener(this);

如果您不想要 activity 实现 NewListDialogListener 那么您可以传递一个侦听器。

NewListDialog dialog = new NewListDialog(this);
dialog.setNewListDialogListener(new NewListDialog.NewListDialogListener() {
    @Override
    public void createListName(String listname) {
        // TODO: Your code here
    }
});

您可以使用 RxAndroid 而不是使用侦听器,在这种情况下,我使用 RxAndroid 从对话框到活动或片段获取数据。

只需要创建一个PublishSubject并获取观测数据即可。在 activity 或片段上:

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    PublishSubject<String > objectPublishSubject = PublishSubject.create();
    objectPublishSubject.observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.newThread())
            .subscribe(this::onNext);
    CustomDialog customDialog = new CustomDialog(this, objectPublishSubject);
    customDialog.show();
}

private void onNext(String data) {
    Log.i("DIALOG_DATA", data);
}

您可以像这样创建对话框:

public class CustomDialog 扩展了 Dialog 实现 View.OnClickListener {

private PublishSubject<String> subject;
public CustomDialog(@NonNull Context context, PublishSubject<String> subject) {
    super(context);
    this.subject = subject;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.custom_dialog);
    findViewById(R.id.button).setOnClickListener(this);

}

@Override
public void onClick(View v) {
    subject.onNext("Data");
    dismiss();
}