Android 小話設(shè)計模式 之 從觀察者到EventBus和RxJava

  設(shè)計模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗(yàn)的總結(jié)。使用設(shè)計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無疑問,設(shè)計模式于己于他人于系統(tǒng)都是多贏的;設(shè)計模式使代碼編制真正工程化;設(shè)計模式是軟件工程的基石脈絡(luò),如同大廈的結(jié)構(gòu)一樣。

前言

軟件工程中的23種設(shè)計模式,相信大家耳熟能詳,在大Java中完美適用,直接上圖(自己畫的):


Design Pattern.png

  這里主要給大家介紹一下神奇且常見的觀察者模式,及其引申出的一些強(qiáng)大用法:CallBack,EventBus,RxJava。

觀察者模式

觀察者模式(Observer)完美的將觀察者和被觀察的對象分離開,定義了對象間的一種一對多的依賴關(guān)系,以便一個對象的狀態(tài)發(fā)生變化時,所有依賴于它的對象都得到通知并自動刷新。
  簡單的來說,打個比方,就類似于獄警時時刻刻盯著犯人,犯人作出一點(diǎn)小動作,那么獄警便立馬做出回應(yīng),反之則相安無事。在Android中的點(diǎn)擊事件監(jiān)聽setOnClickListener( )便完成對接這一概念,即:觀察者將自己注冊到被觀察對象中,被觀察對象將觀察者存放在一個容器里。被觀察對象發(fā)生了某種變化時,從容器中得到所有注冊過的觀察者,將變化通知觀察者從而達(dá)到一個時時監(jiān)聽的作用。
  觀察者(Observer)模式,又叫做發(fā)布訂閱(Publish/Subscribe)模式,下面給出一張經(jīng)典的觀察者模式的關(guān)系對應(yīng)圖,看完大致都明白了吧~


Observer Pattern.png

強(qiáng)大的應(yīng)用之處

觀察者模式相信大家都有了一個了解,在Android中最基本的實(shí)現(xiàn)就是對點(diǎn)擊事件的監(jiān)聽了,相信網(wǎng)上關(guān)于觀察者與setOnClickListener( )的關(guān)系介紹有很多很多咯,這里介紹兩種更高級的應(yīng)用場景,看完你便會完美體會到其強(qiáng)大之處!


Observer Relation.png
  • EventBus

EventBus是Android下高效的發(fā)布/訂閱事件總線機(jī)制。是基于JVM內(nèi)部的數(shù)據(jù)傳輸系統(tǒng),其核心對象為Event和EventHandler。作用是可以代替?zhèn)鹘y(tǒng)的Intent,Handler,Broadcast或接口函數(shù)在Fragment,Activity,Service,線程之間傳遞消息,優(yōu)點(diǎn)是開銷小,代碼更優(yōu)雅,以及將發(fā)送者和接收者解耦。
  看完概念是不是感覺強(qiáng)大的EventBus已經(jīng)無所不能了!那么就從源碼層面分析下其強(qiáng)大的原因:
  汗!在看源碼之前還是先看一下用法吧:

0、Prepare

  Gradle:
        compile 'org.greenrobot:eventbus:3.0.0'
  Maven:
        <dependency>
              <groupId>org.greenrobot</groupId>
              <artifactId>eventbus</artifactId>
              <version>3.0.0</version>
        </dependency>

1、定義關(guān)系:寫一個類描述被觀察者和觀察者之間統(tǒng)一事件關(guān)系,可以為空,也可以加上參數(shù)并通過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、發(fā)布事件頁面:將之前定義在事件關(guān)系的類發(fā)布。

  EventBus.getDefault().post(new Event());

4、接收事件頁面:重寫onEvent...( )方法,通過注解的方法鑒別類型,接收消息(4種方式)。

  @Subscribe(threadMode = ThreadMode.MainThread) 
  //在ui線程執(zhí)行 
  public void onEvent(Event event) { 
          // TODO
  }

  @Subscribe(threadMode = ThreadMode.BackgroundThread) 
  //在后臺線程執(zhí)行 
  public void onEvent(Event event) { 
        // TODO
  }

  @Subscribe(threadMode = ThreadMode.Async) 
  //強(qiáng)制在后臺執(zhí)行 
  public void onEvent(Event event) { 
        // TODO
  }

  @Subscribe(threadMode = ThreadMode.PostThread) 
  //默認(rèn)方式, 在發(fā)送線程執(zhí)行 
  public void onEvent(Event event) { 
        // TODO
  }

綜上,一個Event就對應(yīng)一個關(guān)系,在發(fā)布與接收者之間通過該標(biāo)識的Event就可以自動識別作出響應(yīng)。參考一下3.0之前在接收頁面的接收方法,對應(yīng)上面的(注:在EventBus3.0已經(jīng)將原有的方法改版):

   - onEventMainThread():
        不論事件是在哪個線程中發(fā)布出來的,onEventMainThread都會在UI線程中執(zhí)行。
        在Android中只能在UI線程中更新UI,所以在onEvnetMainThread方法中是不能執(zhí)行耗時操作的。

  - onEventBackgroundThread():
        如果事件是在UI線程中發(fā)布出來的,那么onEventBackground就會在子線程中運(yùn)行。
        如果事件本來就是子線程中發(fā)布出來的,那么onEventBackground函數(shù)直接在該子線程中執(zhí)行。

  - onEventAsync():
        無論事件在哪個線程發(fā)布,都會創(chuàng)建新的子線程在執(zhí)行onEventAsync()。

  - onEvent():
        發(fā)布事件和接收事件線程在同一個線程。
        使用這個方法時,在onEvent方法中不能執(zhí)行耗時操作。
        如果執(zhí)行耗時操作容易導(dǎo)致事件分發(fā)延遲。

下面簡單分析一下源碼,參考了鴻洋大神的帖子,從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;
  }

使用了雙重判斷的方式,防止并發(fā)的問題,還能極大的提高效率。再看一下普通的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);
  }

再點(diǎn)進(jìn)去看看內(nèi)部核心的register(subscriber...)方法:

  private synchronized void register(Object subscriber, String methodName, boolean sticky, int priority) {
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(), methodName);
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
              subscribe(subscriber, subscriberMethod, sticky, priority);
        }
  }

即遍歷該類內(nèi)部所有方法,然后根據(jù)methodName去匹配,匹配成功的封裝成SubscriberMethod,最后返回一個List。繼續(xù)深入的subscribe( )方法在這里就不貼代碼了,有興趣的童鞋可以自己無限往下點(diǎn)點(diǎn)看。
  register( )方法的核心便是:掃描了所有的方法,把匹配的方法最終保存在subscriptionsByEventType( )中,該方法中的eventType是我們方法參數(shù)的Class,Subscription中則保存著subscriber,subscriberMethod(method, threadMode, eventType),priority,包含了執(zhí)行改方法所需的一切。
  其余的一些post( )方法等其實(shí)的本質(zhì)與上方類似,關(guān)于整個EventBus的流程可以大致梳理如下:EventBus負(fù)責(zé)訂閱對象與事件的管理,比如注冊、注銷以及發(fā)布事件等。在初始時將某個對象注冊到EventBus中,EventBus會遍歷該對象class中的所有方法,把參數(shù)數(shù)量為1且用了Subscriber注解標(biāo)識的函數(shù)管理起來,以事件類型和訂閱函數(shù)Subscriber的tag構(gòu)建一個EventType作為一種事件類型,某個事件類型對應(yīng)有一個接收者列表。當(dāng)有事件發(fā)布時,EventBus會根據(jù)發(fā)布的事件類型與tag構(gòu)建EventType,然后找到對應(yīng)的訂閱者列表,并且將這些事件投遞給所有訂閱者。SubscriberMethodHunter負(fù)責(zé)查找合適的EventType,而EventHandler則負(fù)責(zé)將這些訂閱函數(shù)執(zhí)行到相應(yīng)的線程中。

  • RxJava

Reactive Extensions編程簡稱Rx編程,又叫響應(yīng)式編程,提供一致的編程接口,幫助開發(fā)者更方便的處理異步數(shù)據(jù)流,使軟件開發(fā)更高效、更簡潔。其中,對于異步錯誤處理,傳統(tǒng)的try/catch沒辦法處理異步計算,Rx提供了合適的錯誤處理機(jī)制輕松使用并發(fā)。而Rx的Observables和Schedulers讓開發(fā)者可以擺脫底層的線程同步和各種并發(fā)問題。
  關(guān)于RxJava的基本實(shí)現(xiàn)很簡單,看如下三步:

1、創(chuàng)建一個Observable對象,直接調(diào)用Observable.create( ):

  Observable<String> myObservable = Observable.create(
        new Observable.OnSubscribe<String>() {
              @Override
              public void call(Subscriber<? super String> sub) {
                    sub.onNext("Hello, world!");
                    sub.onCompleted();
              }
        }
  );

2、創(chuàng)建一個Subscriber來處理Observable對象發(fā)出的字符串:

  Subscriber<String> mySubscriber = new Subscriber<String>() {
        @Override
        public void onNext(String s) { 
              System.out.println(s); 
        }

        @Override
        public void onCompleted() {
              // TODO
        }

        @Override
        public void onError(Throwable e) {
              // TODO
        }
  };

3、通過subscribe函數(shù)就可以將myObservable對象和mySubscriber對象關(guān)聯(lián)綁定起來,完成subscriber對observable的訂閱:

  myObservable.subscribe(mySubscriber);

當(dāng)然,強(qiáng)大的RxJava提供了一些方法使代碼簡化,如just( ),map( ),Action1類等等,如:

  Observable.just("Hello, world!")
        .subscribe(new Action1<String>() {
              @Override
              public void call(String s) {
                    System.out.println(s);
              }
        });

  Observable.just("Hello, world!")
        .map(new Func1<String, String>() {
              @Override
              public String call(String s) {
                    return s + "Ivor";
              }
        }).subscribe(new Action1<String>() {
              @Override
              public void call(String s) {
                    System.out.println(s);
              }
        });

關(guān)于RxJava的基本使用大致就介紹到這里,后續(xù)關(guān)于RxJava和Retrofit以及RxAndroid的引申下期會更新,大家也可以提前參考一下福生寶寶的RxJava 的使用與理解(二)。

  • EventBus VS RxJava

RxJava要比EventBus的應(yīng)用更廣泛,EventBus僅僅是作為一種消息的傳遞工具,但是RxJava里面幾乎可以做任何事情,只是對于簡單的業(yè)務(wù)來說可能有些冗余,EventBus相對來說更加輕量,EventBus有個缺點(diǎn)就是凡是使用了EventBus的類都不能進(jìn)行混淆了,否則Evnetbus就找不到OnEvent方法了。

尾聲

關(guān)于觀察者模式的應(yīng)用有很多,這里先介紹這么兩種強(qiáng)大的庫,供大家參考學(xué)習(xí)~~請將強(qiáng)大的Observer與Listener發(fā)揮到極致:)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容