Rxjava前篇(一):观察者模式之接口回调

来源:互联网 发布:access2000数据库修复 编辑:程序博客网 时间:2024/06/01 10:52

如理解有误或者模棱两可的地方,欢迎指出。共同进步,一起成长!

前言:为什么要了解观察者模式?
- 最近准备入手retrofit就遇到了RxJava(由于入坑晚+公司框架太老以至于到现在才开始自学rxJava);RxJava的异步让人佩服,切换线程只需一行代码,序列化事件链式操作……各种Obsever、Observable于是引出了观察者模式。
- 熟悉接口回调的能很快看懂观察者模式。

PS:个人认为学以致用,研究茴香豆有几种写法没有意义,但是我们要知其所以然,只会调api就显得很Low了哇。当我们用api出现问题,或者不能满足需求的时候,我们就得往底层看,去看源码,弄懂实现原理。懂了,才敢放心的用各种操作拼凑起来满足自己的需求。
天线式装逼.jpg

本篇主要分为:
- 通用接口回调套路
- view click回调事件简单分析
- 接口回调对象的传递(主要是单例模式)

正文:观察者模式先来看看接口回调

接口回调异步是怎么实现的?
接口注册、实现和接口调用分离
总的来说就分三步走:
1.定义一个接口(待实现的抽象方法)
2.实现接口并注册接口
3.调用接口方法(这里一般是一个类,拥有刚才定义的接口,并对外提供注册接口的方法)然后回调到实现接口的地方执行

下面以我们常用的点击事件回调看一下:

  • 实现接口并注册接口
//at mainActivity   bt.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Log.v("tag","ui主线程发送msg "+"当前线程: "+Thread.currentThread().getId());                testThread.mhandler.sendEmptyMessage(0);            }        });

跟进去看一下View.OnClickListener()接口,其实从这儿可以看到接口是在View内部的
- 定义一个接口

public interface OnClickListener {        void onClick(View v);    }

就一个很简单的抽象方法,接口方法默认是public abstract,可以省略

  • 调用接口方法(简单分析下点击事件,不感兴趣的可以直接跳过performclick)
    都是在view.class里面,方便查看省略了很多代码
    可以看到点击事件经过事件分发机制,经过事件分发拦截处理,最后来到view的dispatchTouchEvent(不了解事件分发机制的同学可以自行google,后面有空也会分享一点心得)
public boolean dispatchTouchEvent(MotionEvent event) {//....................ListenerInfo li = mListenerInfo;            if (li != null && li.mOnTouchListener != null                    && (mViewFlags & ENABLED_MASK) == ENABLED                    && li.mOnTouchListener.onTouch(this, event)) {                 result = true;     //决定是否调用onTouchEvent            }            if (!result && onTouchEvent(event)) {  //result如果为flase这里调用onTouchEvent                result = true;            }}//............

可以看到如果上面li.mOnTouchListener.onTouch(this, event)返回为true,result为true; resulet如果为true,往下就不会执行ontouchEvent(进而执行click)了。
这也是为什么在重写ontouch返回为true,对应view的click事件不会响应。

onTouchEvent里面会调用performClick。注意是action_up的时候才会调用哦,也就是手指头按下不会,松开才会回调click事件。不知道平时大家有没有注意,不知道的还不赶紧试试= =

public boolean onTouchEvent(MotionEvent event) {//........... case MotionEvent.ACTION_UP:if (!focusTaken) {                                                      if (mPerformClick == null) {                                    mPerformClick = new PerformClick();                                }                                if (!post(mPerformClick)) {                                    performClick(); //====这里调用performClick                                }                            }}//...........

下面代码可以看到如果mlickListener不为null就可以执行onclick方法,回调到注册接口那里执行。当然对对象判空是一种意识,不然如果忘了注册接口,就不仅仅是不能触发回调,而是直接空指针异常闪退了。

//at View.class public boolean performClick() {        final boolean result;        final ListenerInfo li = mListenerInfo;        if (li != null && li.mOnClickListener != null) {            playSoundEffect(SoundEffectConstants.CLICK);            li.mOnClickListener.onClick(this);  //=====这里调用接口的onclick            result = true;        } else {            result = false;        }        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);        return result;    }

就是这么简单.JPG
虽然看起来代码很多,那是因为android为了实现各种view事件复杂逻辑的代码。我们自己的逻辑如果比较简单,直接获取到subject,然后通过它的接口调用一下方法就行啦。

贴一个自己写的简单接口回调demo

//接口CallBackInterface public interface CallBackInterface {    void onCallBack();}//Subject.class public class Subject {    private CallBackInterface callBackInterface;    public void setCallBackInterface(CallBackInterface callBackInterface){        this.callBackInterface = callBackInterface;    }    public void notifyCallBack(){        if(callBackInterface != null) {            callBackInterface.onCallBack();        }    }  //一般情况是在这个类调用notifyCallBack();比如突然断网、数据库更新等。如果在其他地方调用,需要获取到subject这个注册了接口的对象。}//mainActivityprivate Subject subject = new Subject(); //获取subjuect对象是重点subject.setCallBackInterface(new CallBackInterface() {            @Override            public void onCallBack() {                Log.v("tag","at mainActivity  11111");            }        });//secondeActivityprivate Subject subject; //这个subject要是mainActivity 注册的那个对象,比如用构造函数,set等方法传过来。subject.notifyCallBack();

其实我觉得接口回调3步走没什么毛病。主要是subject.setCallBackInerface()和subject.notifyCallBack()的subject要是同一个对象。
ps:不要觉得没对象就随便new一个……..FFFFFF
如果callBackInterface.onCallBack()在Subject类里面调用,那没什么毛病。如果是在其他地方调用,就要考虑下这个subject注册和调用的地方传递。
- 上面的demo可以用intent传,不过subject要可序列化,所有Subject要实现Parcelable接口。
- 普通的类也可以用构造函数传过去。
- 如果确定Subject对象只有一个(即单例),那么用单例模式是最方便的了。
- 其他方法(骚操作)
举个例子.jpg

Subject换成单例就变成下面这样,注意看注释

/** * Created by Dynamic on 2017/11/2. */public class Subject  {    private static volatile Subject singleSubject; //volatile是由于jdk1.5之前的漏洞    private Subject(){ //构造函数私有,确保单例的关键    }    public static  Subject getInstance(){        if(singleSubject == null){  //懒汉式,只有需要用到它的时候才去new,不是一开始就new出来            synchronized (Subject.class){   //线程同步,避免多线程同时执行,new很多个出来(单例)                if(singleSubject == null){                     // 双重检查;因为同步块里面第一个null去new,执行完后,已经不为Nulll了                    //如果singleSubject有了,后面的线程就没必要再去new了                    singleSubject = new Subject();                }            }        }        return singleSubject;    }    private CallBackInterface callBackInterface;    public void setCallBackInterface(CallBackInterface callBackInterface){        this.callBackInterface = callBackInterface;    }    public void notifyCallBack(){        if(callBackInterface != null) {            callBackInterface.onCallBack();        }    }}

上面使用的是最安全的单例模式了,不管在什么地方哪个类里面,只需要Subject.getInstance,拿到的就一定是同一个subject,非常方便。

可能有人会问接口回调能干什么呢?
- 当然是异步啦。像上面的demo,mainActivity注册完接口后,就去干其他事情了,不用等着secondActiviy调用callBack。接口调用的回调通知回来的时候,才去处理回调。
- 类A(如网络管理类)的事件(wifi断开)回调到类B(数据库管理类)处理(入库断开的事件),就可以访问B的私有成员变量和方法了。(以前不知道接口回调,还是用的handler通信 == )

下一篇我会以自己的看法来讲述一下观察者模式:以前刚听到这个模式的时候,觉得被观察者好可怜,被围观。后面渐渐发现被观察者才是老大啊,所有信号都是它发的发出来的,然后一群观察者去响应。怎么说呢,就好像是大家(可以规划到一个类集合里面)都在干活。老板突然说了句发工资了,然后大家全部去响应领工资,而且每个员工各自领的工资不一样(每个观察者实现回调不一样)。

原创粉丝点击