[读书笔记]监听事件的四种方式原理分析(接口回调)与比较

来源:互联网 发布:影视后期网络培训学校 编辑:程序博客网 时间:2024/06/07 08:41
  • 方式一:在布局文件的控件上设置onClick属性

布局文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="match_parent"              android:orientation="vertical">    <Button        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:onClick="sayHello"        android:text="HELLO"/></LinearLayout>

在源文件中绑定点击事件:

/** * ============================================================================= * Copyright (c) 2016 yuxin All rights reserved. * Packname work * Created by yuxin. * Created time 2016/9/21 0021 上午 8:38. * Version   1.0; * Describe : * History: * ============================================================================== */public class LoginOkActivity2 extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.dome);    }    public void doClick(View view) {        //do something    }}

这种方式代码简洁,结构清晰,唯一的缺点是android:onClick注册在debug时能运行正常,切换成release版本时release版本通常会混淆代码,方法的名称就改变了,所以这种方式虽然简单,但是不推荐。
在介绍后面几种方法前我们先提下java中方法的回调,下面这图是我对回调的理解:
这里写图片描述
如果还没看懂或则觉得我的理解有问题的,可以baidu看下别人的解释

  • 方式二:匿名内部类作为事件监听器类
/** * ============================================================================= * Copyright (c) 2016 yuxin All rights reserved. * Packname com.jju.yuxin.disanzhou * Created by yuxin. * Created time 2016/9/21 0021 上午 10:50. * Version   1.0; * Describe : * History: * ============================================================================== */public class ClickDome extends Activity {    private Button bt_click;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_click);        bt_click = (Button) findViewById(R.id.bt_click);        bt_click.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //do  something            }        });    }}

很多监听事件只是临时的使用一次,或则有的一类监听操作只有一个控件执行,那么可以使用这种,也是使用比较广泛的一种监听方式,但是对于java来说,这种耦合有点紧,没有模块化的。

  • 方式三:内部类作为监听器
public class ClickDome extends Activity {    private Button bt_click;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_click);        bt_click = (Button) findViewById(R.id.bt_click);        MyClickListener listtener = new MyClickListener():        bt_click.setOnClickListener(listtener);    }    private class MyClickListener implements View.OnClickListener {        @Override        public void onClick(View v) {            switch (v.getId()) {                case R.id.bt_click:                    break;                default:                    break;            }        }    }}

当然也可以将内部类放置出来另写一个监听类,这种方式在java上符合单一职责原则,耦合度低,但是带来的确实更多的代码编写量,庆幸的是带来了可复用性,只要同一类监听操作我们都只传入一个监听类对象搞定,然后在switch中写上代码,但是记得的是,不同的activity千万别放在一个监听类里面操作,可能一时爽,痛苦起来会发疯。

  • 方式四:Activity继承监听事件,Activity本身作为事件监听器
/** * ============================================================================= * Copyright (c) 2016 yuxin All rights reserved. * Packname com.jju.yuxin.disanzhou * Created by yuxin. * Created time 2016/9/21 0021 上午 10:50. * Version   1.0; * Describe : * History: * ============================================================================== */public class ClickDome extends Activity implements View.OnClickListener {    private Button bt_click;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_click);        bt_click = (Button) findViewById(R.id.bt_click);        bt_click.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.bt_click:        //do something                break;            default:                break;        }    }}

这种方法其实和上面的方式三差不多,在这种方式里,监听类的对象都不用new了,因为就是本身,传入一个this就行了,但是你不觉得Activity一个界面类来实现监听接口有点不伦不类嘛?

综合上面四种方式,各有各的优势与劣势,在实际场景中灵活运用才是正道。
这博客就写完了嘛??不不不,,本博主和哪些妖艳贱货不一样,肯定要写点其他的东西啊,不然前面的方法回调不是白白铺垫了嘛,我们仔细的看下后面三种方式,其实原理都一样,都是为了实现onClick()这个方法,我们来看下setOnClickListener();这个方法,因为Buttom是View的子类,我们看下View里面的setOnClickListener()方法,

 /**     * Register a callback to be invoked when this view is clicked. If this view is not     * clickable, it becomes clickable.     *     * @param l The callback that will run     *     * @see #setClickable(boolean)     */    public void setOnClickListener(@Nullable OnClickListener l) {        if (!isClickable()) {            setClickable(true);        }        getListenerInfo().mOnClickListener = l;    }

他就做了两件事情,一、把控件置为可点击的,二、将OnClickListener 对象赋值给getListenerInfo方法里面的mOnClickListener属性,我们看下这两个方法:

  /**     * Enables or disables click events for this view. When a view     * is clickable it will change its state to "pressed" on every click.     * Subclasses should set the view clickable to visually react to     * user's clicks.     *     * @param clickable true to make the view clickable, false otherwise     *     * @see #isClickable()     * @attr ref android.R.styleable#View_clickable     */    public void setClickable(boolean clickable) {        setFlags(clickable ? CLICKABLE : 0, CLICKABLE);    }

他在这里立了个flag

   ListenerInfo getListenerInfo() {        if (mListenerInfo != null) {            return mListenerInfo;        }        mListenerInfo = new ListenerInfo();        return mListenerInfo;    }

这里也是非空判断下,返回个属性
这下我慌了,下一步它往哪里走呢??后来我看到了这个方法boolean performAccessibilityActionInternal(int action, Bundle arguments)(名字有点长)

   /**    * @see #performAccessibilityAction(int, Bundle)    *    * Note: Called from the default {@link AccessibilityDelegate}.    *    * @hide    */    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {                      .                      .                      .                      .        switch (action) {            case AccessibilityNodeInfo.ACTION_CLICK: {                if (isClickable()) {                    performClick();                    return true;                }            } break;                  .                  .                  .        return false;    }

中间其他的我们都不关系,我们看下注释Note: Called from the default {@link AccessibilityDelegate}.大概意思就是说它会被另一个方法默认调用,我们看下switch

 /**     * Indicates whether this view reacts to click events or not.     *     * @return true if the view is clickable, false otherwise     *     * @see #setClickable(boolean)     * @attr ref android.R.styleable#View_clickable     */    @ViewDebug.ExportedProperty    public boolean isClickable() {        return (mViewFlags & CLICKABLE) == CLICKABLE;    }

这个isClickable()就是返回之前setClickable()的值,我记得方法一进来就设置为了true,那我们看下performClick();

 /**     * Call this view's OnClickListener, if it is defined.  Performs all normal     * actions associated with clicking: reporting accessibility event, playing     * a sound, etc.     *     * @return True there was an assigned OnClickListener that was called, false     *         otherwise is returned.     */    public boolean performClick() {        final boolean result;        final ListenerInfo li = mListenerInfo;        if (li != null && li.mOnClickListener != null) {            playSoundEffect(SoundEffectConstants.CLICK);            li.mOnClickListener.onClick(this);            result = true;        } else {            result = false;        }        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);        return result;    }

其他的都不重要。我们看到它通过各种传递和判断,将我们传进来的OnClickListener对象调用它的onClick()方法;。。而我们来看下onClick()

   /**     * Interface definition for a callback to be invoked when a view is clicked.     */    public interface OnClickListener {        /**         * Called when a view has been clicked.         *         * @param v The view that was clicked.         */        void onClick(View v);    }

他是View类里面的OnClickListener接口的一个没有实现的方法,而这个方法就是我们在监听类里面实现的void onClick(View v)方法,结合之前的方法回调的图,这个应该知道工作模式了把!
关于绑定监听事件的原理应该是在LayoutInflater.from(this).inflate();实现,里面有对资源XML的解析生成View树图,但是原理我还没看,有兴趣的可以自己看下

我的博客网站http://huyuxin.top/欢迎大家访问!评论!

1 0