设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
前言
软件工程中的23种设计模式,相信大家耳熟能详,在大Java中完美适用,直接上图(自己画的):
这里主要给大家介绍一下神奇且常见的观察者模式,及其引申出的一些强大用法:CallBack,EventBus,RxJava。
观察者模式
观察者模式(Observer)完美的将观察者和被观察的对象分离开,定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
简单的来说,打个比方,就类似于狱警时时刻刻盯着犯人,犯人作出一点小动作,那么狱警便立马做出回应,反之则相安无事。在Android中的点击事件监听setOnClickListener( )便完成对接这一概念,即:观察者将自己注册到被观察对象中,被观察对象将观察者存放在一个容器里。被观察对象发生了某种变化时,从容器中得到所有注册过的观察者,将变化通知观察者从而达到一个时时监听的作用。
观察者(Observer)模式,又叫做发布订阅(Publish/Subscribe)模式,下面给出一张经典的观察者模式的关系对应图,看完大致都明白了吧~
强大的应用之处
观察者模式相信大家都有了一个了解,在Android中最基本的实现就是对点击事件的监听了,相信网上关于观察者与setOnClickListener( )的关系介绍有很多很多咯,这里介绍两种更高级的应用场景,看完你便会完美体会到其强大之处!
-
EventBus
EventBus是Android下高效的发布/订阅事件总线机制。是基于JVM内部的数据传输系统,其核心对象为Event和EventHandler。作用是可以代替传统的Intent,Handler,Broadcast或接口函数在Fragment,Activity,Service,线程之间传递消息,优点是开销小,代码更优雅,以及将发送者和接收者解耦。
看完概念是不是感觉强大的EventBus已经无所不能了!那么就从源码层面分析下其强大的原因:
汗!在看源码之前还是先看一下用法吧:
0、Prepare:
Gradle:
compile 'org.greenrobot:eventbus:3.0.0'
Maven:
org.greenrobot
eventbus
3.0.0
1、定义关系:写一个类描述被观察者和观察者之间统一事件关系,可以为空,也可以加上参数并通过get/set方法绑定。
public class Event {
public Event() {
// TODO
}
}
2、接收事件页面:注册与销毁。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 注册EventBus
EventBus.getDefault().register(this);
}
// TODO
@Override
protected void onDestroy(){
super.onDestroy();
// 销毁EventBus
EventBus.getDefault().unregister(this);
}
3、发布事件页面:将之前定义在事件关系的类发布。
EventBus.getDefault().post(new Event());
4、接收事件页面:重写onEvent...( )方法,通过注解的方法鉴别类型,接收消息(4种方式)。
@Subscribe(threadMode = ThreadMode.MainThread)
//在ui线程执行
public void onEvent(Event event) {
// TODO
}
@Subscribe(threadMode = ThreadMode.BackgroundThread)
//在后台线程执行
public void onEvent(Event event) {
// TODO
}
@Subscribe(threadMode = ThreadMode.Async)
//强制在后台执行
public void onEvent(Event event) {
// TODO
}
@Subscribe(threadMode = ThreadMode.PostThread)
//默认方式, 在发送线程执行
public void onEvent(Event event) {
// TODO
}
综上,一个Event就对应一个关系,在发布与接收者之间通过该标识的Event就可以自动识别作出响应。参考一下3.0之前在接收页面的接收方法,对应上面的(注:在EventBus3.0已经将原有的方法改版):
- onEventMainThread():
不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行。
在Android中只能在UI线程中更新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
- onEventBackgroundThread():
如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行。
如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
- onEventAsync():
无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync()。
- onEvent():
发布事件和接收事件线程在同一个线程。
使用这个方法时,在onEvent方法中不能执行耗时操作。
如果执行耗时操作容易导致事件分发延迟。
下面简单分析一下源码,参考了鸿洋大神的帖子,从register( )方法入手,先看getDefault( ):
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
使用了双重判断的方式,防止并发的问题,还能极大的提高效率。再看一下普通的register( )方法:
public void register(Object subscriber) {
register(subscriber, DEFAULT_METHOD_NAME, false, 0);
}
public void register(Object subscriber, int priority) {
register(subscriber, DEFAULT_METHOD_NAME, false, priority);
}
public void registerSticky(Object subscriber) {
register(subscriber, DEFAULT_METHOD_NAME, true, 0);
}
public void registerSticky(Object subscriber, int priority) {
register(subscriber, DEFAULT_METHOD_NAME, true, priority);
}
再点进去看看内部核心的register(subscriber...)方法:
private synchronized void register(Object subscriber, String methodName, boolean sticky, int priority) {
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(), methodName);
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
即遍历该类内部所有方法,然后根据methodName去匹配,匹配成功的封装成SubscriberMethod,最后返回一个List。继续深入的subscribe( )方法在这里就不贴代码了,有兴趣的童鞋可以自己无限往下点点看。
register( )方法的核心便是:扫描了所有的方法,把匹配的方法最终保存在subscriptionsByEventType( )中,该方法中的eventType是我们方法参数的Class,Subscription中则保存着subscriber,subscriberMethod(method, threadMode, eventType),priority,包含了执行改方法所需的一切。
其余的一些post( )方法等其实的本质与上方类似,关于整个EventBus的流程可以大致梳理如下:EventBus负责订阅对象与事件的管理,比如注册、注销以及发布事件等。在初始时将某个对象注册到EventBus中,EventBus会遍历该对象class中的所有方法,把参数数量为1且用了Subscriber注解标识的函数管理起来,以事件类型和订阅函数Subscriber的tag构建一个EventType作为一种事件类型,某个事件类型对应有一个接收者列表。当有事件发布时,EventBus会根据发布的事件类型与tag构建EventType,然后找到对应的订阅者列表,并且将这些事件投递给所有订阅者。SubscriberMethodHunter负责查找合适的EventType,而EventHandler则负责将这些订阅函数执行到相应的线程中。
-
RxJava
Reactive Extensions编程简称Rx编程,又叫响应式编程,提供一致的编程接口,帮助开发者更方便的处理异步数据流,使软件开发更高效、更简洁。其中,对于异步错误处理,传统的try/catch没办法处理异步计算,Rx提供了合适的错误处理机制轻松使用并发。而Rx的Observables和Schedulers让开发者可以摆脱底层的线程同步和各种并发问题。
关于RxJava的基本实现很简单,看如下三步:
1、创建一个Observable对象,直接调用Observable.create( ):
Observable myObservable = Observable.create(
new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> sub) {
sub.onNext("Hello, world!");
sub.onCompleted();
}
}
);
2、创建一个Subscriber来处理Observable对象发出的字符串:
Subscriber mySubscriber = new Subscriber() {
@Override
public void onNext(String s) {
System.out.println(s);
}
@Override
public void onCompleted() {
// TODO
}
@Override
public void onError(Throwable e) {
// TODO
}
};
3、通过subscribe函数就可以将myObservable对象和mySubscriber对象关联绑定起来,完成subscriber对observable的订阅:
myObservable.subscribe(mySubscriber);
当然,强大的RxJava提供了一些方法使代码简化,如just( ),map( ),Action1类等等,如:
Observable.just("Hello, world!")
.subscribe(new Action1() {
@Override
public void call(String s) {
System.out.println(s);
}
});
Observable.just("Hello, world!")
.map(new Func1() {
@Override
public String call(String s) {
return s + "Ivor";
}
}).subscribe(new Action1() {
@Override
public void call(String s) {
System.out.println(s);
}
});
关于RxJava的基本使用大致就介绍到这里,后续关于RxJava和Retrofit以及RxAndroid的引申下期会更新,大家也可以提前参考一下福生宝宝的RxJava 的使用与理解(二)。
-
EventBus VS RxJava
RxJava要比EventBus的应用更广泛,EventBus仅仅是作为一种消息的传递工具,但是RxJava里面几乎可以做任何事情,只是对于简单的业务来说可能有些冗余,EventBus相对来说更加轻量,EventBus有个缺点就是凡是使用了EventBus的类都不能进行混淆了,否则Evnetbus就找不到OnEvent方法了。
尾声
关于观察者模式的应用有很多,这里先介绍这么两种强大的库,供大家参考学习~~请将强大的Observer与Listener发挥到极致:)
附在线流程图制作网站
https://www.processon.comAndroid EventBus源码解析 带你深入理解EventBus
http://blog.csdn.net/lmj623565791/article/details/40920453RxJava 的使用与理解(一)
http://www.jianshu.com/p/f564104958b8Github地址:
https://github.com/IvorfasonGithub博客:
http://ivorfason.github.io新浪博客
http://blog.sina.com.cn/u/1780835484个人网站:
http://www.ivorfason.site个人邮箱:(我觉得QQ邮箱很高大上,You can you up!)
[email protected]杂谈一下
这里只是简单的给大家介绍了一下用法和基本的实现方式,大家可以直接拿来写Demo,在实际应用中,一个简单的EventBus便可省去许多代码,一个简单的RxJava便可省去许多逻辑,但是自己写的时候还会有一些坑要踩,合理地应用好观察者模式,你会变得很强大!You can you up!