Android开发Android知识Android技术知识

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

2017-11-03  本文已影响91人  Dynamic_2018

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

前言:为什么要了解观察者模式?

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


天线式装逼.jpg

本篇主要分为:

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

接口回调异步是怎么实现的?
接口注册、实现和接口调用分离
总的来说就分三步走:
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,可以省略

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这个注册了接口的对象。
}
//mainActivity
private Subject subject = new Subject(); //获取subjuect对象是重点
subject.setCallBackInterface(new CallBackInterface() {
            @Override
            public void onCallBack() {
                Log.v("tag","at mainActivity  11111");
            }
        });



//secondeActivity
private Subject subject; //这个subject要是mainActivity 注册的那个对象,比如用构造函数,set等方法传过来。
subject.notifyCallBack();

其实我觉得接口回调3步走没什么毛病。主要是subject.setCallBackInerface()和subject.notifyCallBack()的subject要是同一个对象。
ps:不要觉得没对象就随便new一个........FFFFFF
如果callBackInterface.onCallBack()在Subject类里面调用,那没什么毛病。如果是在其他地方调用,就要考虑下这个subject注册和调用的地方传递。

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,非常方便。

关于单例模式

可能有人会问接口回调能干什么呢?

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

上一篇下一篇

猜你喜欢

热点阅读