首页 > 自己写的 interface 为什么能作为监听器?

自己写的 interface 为什么能作为监听器?

Android 里面自定义监听器我没搞明白. 监听器是能够做到每时每刻监听是吗? 那像这些自己写出来的监听器究竟是怎么做到监听的?

像这个Android 帮助文档上的实现 dialog 的代码(代码如下), 自己编的一个 interface 被 MainActivity 继承为什么就能做到监听? — NoticeDialogListener为什么能够接收到点击按钮的事件呢?

以下是上述文档的代码. 当然我问的也不仅仅是这个代码了… 谢谢回答!

For example, here's a DialogFragment that defines an interface through
which it delivers the events back to the host activity:

public class NoticeDialogFragment extends DialogFragment {

    /* The activity that creates an instance of this dialog fragment must
     * implement this interface in order to receive event callbacks.
     * Each method passes the DialogFragment in case the host needs to query it. */
    public interface NoticeDialogListener {
        public void onDialogPositiveClick(DialogFragment dialog);
        public void onDialogNegativeClick(DialogFragment dialog);
    }

    // Use this instance of the interface to deliver action events
    NoticeDialogListener mListener;

    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        // Verify that the host activity implements the callback interface
        try {
            // Instantiate the NoticeDialogListener so we can send events to the host
            mListener = (NoticeDialogListener) activity;
        } catch (ClassCastException e) {
            // The activity doesn't implement the interface, throw exception
            throw new ClassCastException(activity.toString()
                    + " must implement NoticeDialogListener");
        }
    }
    ... 
}

The activity hosting the dialog creates an instance of the dialog with
the dialog fragment's constructor and receives the dialog's events
through an implementation of the NoticeDialogListener interface:

public class MainActivity extends FragmentActivity
                          implements NoticeDialogFragment.NoticeDialogListener{
    ...

    public void showNoticeDialog() {
        // Create an instance of the dialog fragment and show it
        DialogFragment dialog = new NoticeDialogFragment();
        dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
    }

    // The dialog fragment receives a reference to this Activity through the
    // Fragment.onAttach() callback, which it uses to call the following methods
    // defined by the NoticeDialogFragment.NoticeDialogListener interface
    @Override
    public void onDialogPositiveClick(DialogFragment dialog) {
        // User touched the dialog's positive button
        ...
    }

    @Override
    public void onDialogNegativeClick(DialogFragment dialog) {
        // User touched the dialog's negative button
        ...
    }
}

Because the host activity implements the NoticeDialogListener—which is enforced by the onAttach() callback
method shown above—the dialog fragment can use the interface callback
methods to deliver click events to the activity:

public class NoticeDialogFragment extends DialogFragment {
    ...

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Build the dialog and set up the button click handlers
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setMessage(R.string.dialog_fire_missiles)
               .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // Send the positive button event back to the host activity
                       mListener.onDialogPositiveClick(NoticeDialogFragment.this);
                   }
               })
               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // Send the negative button event back to the host activity
                       mListener.onDialogNegativeClick(NoticeDialogFragment.this);
                   }
               });
        return builder.create();
    } 
}

这是一种设计模式,只是名字叫监听器,并不是主动触发,是被动的。理解了这种模式你自己就可以写一些,我们通常说的回调就是这个。


这本质上是一个方法调用。假设我们有两个类A和B,我们期望在A的某个时刻调用B的某个方法,我们可以让A保持一个B的引用,在合适的时机进行方法调用:

class B {
    void doSomething() {}
}

class A {
    private B b;
    
    public void setB(B b) {
        // 保持一个B的引用
        this.b = b;
    }
    
    public void testMethod() {
        // ...
        // 在A的某个时刻调用B的某个方法
        b.doSomething();
        // ...
    }
}

以上代码实现了,在A的某个时刻(发生某件事情的时候),我们通知B去做一些事情,这就是一个简单的监听模式。你看,这里并不是B时时刻刻去监听A的动作,而是在某个时刻A主动触发了B的方法。

在这里,把B换成Listener,就变成了我们熟悉的监听器。

所以我们可以写一个B的子类,也就实现了一个自定义监听器:

class SubB extends B {
    @override
    void doSomething() {}
}

void main() {
    A a = new A();
    // 给A设置我们自定义的监听器
    a.setB(new SubB());
    a.testMethod();
}

在设计模式方面,有一条推荐的做法,叫做“多用组合,少用继承”,意思是说应该多用接口而少用继承,我们把上面的B改成接口:

interface B {
    void doSomething();
}

然后把之前继承的实现换成接口的实现:

class SubB implements B {
    void doSomething() {}
}
void main() {
    A a = new A();
    // 给A设置我们自定义的监听器
    a.setB(new SubB());
    a.testMethod();
}

你可以看到,用法和之前是完全一样的。

把interface B换成interface OnClickListener,是不是就清晰很多了?这在设计模式中叫做观察者模式

推荐一本书:《Head First设计模式》,其中前两个章节介绍了策略模式观察者模式,也就是我上面提到的内容。


Java的Listener是规定回调函数的接口。Listener的实现类(一般是匿名内部类)是回调函数对象本身。Java里面要是想传递一个函数对象(也称为闭包),就需要这样做。


不要字面的理解监听器,它不是主动去检查时间是否发生的,所以不存在每时每刻这种说法。
对于我们来说,Android中的Listener其实只是一种Callback,是回调方法。是当事件发生时,由事件发起者或者内部处理者调用的方法。
自己编写的Listener类并不是因为继承了谁谁谁就能监听事件,而是要想办法告诉事件的发起者或者内部处理者,事件发生时,需要调用这个Listener中的指定方法,这也就是通常所要做的setListener的过程。

你给出的代码里已经把这个逻辑演绎得非常清楚,请先仔细看看代码。


很久之前,我学java的时候,也问了同学这个问题,你采纳的那个人已经说很清楚了,这本质是一个方法调用。
其实你只要上课认真听讲了,下课认真把老师打的代码打了一遍,你就明白这个问题了,
可以肯定的是,总是喜欢把问题拖着,到后来再弄清楚,这样是不行的。
建议多打代码,每天不少于700行。
你觉得没代码打?问别人弄清楚的问题,那个代码一定要打3遍,没代码打就打些有意义的小程序。
坚持打代码,就是从一开始就坚持强大。

【热门文章】
【热门文章】