前言
最近在學(xué)習(xí)Rxjava2,雖然在實際的項目中使用也看了很多的文章和文檔,學(xué)會的了如何使用但是忘記的很快,也沒有很好的總結(jié),在學(xué)習(xí)的時做的筆記過了一段時間發(fā)現(xiàn)自己做的筆記都有些看不明白,作為小白的我寫博客還是有點膽戰(zhàn)心驚的,這篇博客的主要的目的是引導(dǎo)沒有了解過Rxjava的人一個參考,講一些簡單的原理和常用操作符及使用場景,可能會有錯誤希望大家多多指教批評,去其糟粕取其精華,那么開始學(xué)習(xí)之旅吧。
概念
我們知道Rxjva使用的是觀察者設(shè)計模式,那么什么是觀察者模式呢?其實我們在開發(fā)中一直使用,只是我們沒用認(rèn)真的去了解,常見按鈕點擊事件就是一個很好的例子。也許現(xiàn)在你還疑惑那么在我講解概念之后回頭在看你就會明白了。首先我們要先了解幾個概念。
-
什么是觀察者模式?
觀察者(Observer)模式:是對象的行為模式,又叫做發(fā)布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監(jiān)聽(Source/Listener)模式或者從屬(Dependents)模式。
抽象主題(Subject)角色:
抽象主題角色把所有對觀察者對象的引用保存在一個聚集(比如ArrayList對象)里,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象,抽象主題角色又叫做抽象被觀察者(Observable)角色。
具體主題(ConcreteSubject)角色:
將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題的內(nèi)部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。具體主題角色又叫做具體被觀察者(Concrete Observable)角色。
抽象觀察者(Observer)角色:
為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己,這個接口叫做更新接口。
具體觀察者(ConcreteObserver)角色:
存儲與主題的狀態(tài)自恰的狀態(tài)。具體觀察者角色實現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài) 像協(xié)調(diào)。如果需要,具體觀察者角色可以保持一個指向具體主題對象的引用。
觀察者模式定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一個主題對象,這個主題對象在狀態(tài)上發(fā)生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。
這是一種比較官方的說法,當(dāng)然每個人的理解不同。簡單來說在觀察者模式中,有兩個對象觀察者(訂閱)和被觀察者(被訂閱),一個被觀察者可以有很多觀察者,當(dāng)被觀察者法神變化的時候,所有的觀察者都會收到通知,從而改變自己(更新自己)。舉個例子:一個課堂上,只會有一個老師(被觀察者)講課,當(dāng)講到一個知識點,每個都同學(xué)(觀察者)聽到老師所講的知識點,有的會做筆記有的會提問(相當(dāng)于所有觀察者接到通知改變自己)。這就是觀察者模式。
-
是觀察者模式圖形分析?

抽象主題(Subject)角色:
抽象主題角色把所有對觀察者對象的引用保存在一個聚集(比如ArrayList對象)里,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象,抽象主題角色又叫做抽象被觀察者(Observable)角色。
具體主題(ConcreteSubject)角色:
將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題的內(nèi)部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。具體主題角色又叫做具體被觀察者(Concrete Observable)角色。
抽象觀察者(Observer)角色:
為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己,這個接口叫做更新接口。
具體觀察者(ConcreteObserver)角色:
存儲與主題的狀態(tài)自恰的狀態(tài)。具體觀察者角色實現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài) 像協(xié)調(diào)。如果需要,具體觀察者角色可以保持一個指向具體主題對象的引用。
從這個關(guān)系圖我們可以看出左側(cè)是被觀察者(Subject/Observable),右側(cè)是觀察者(Observer),他們的關(guān)系是1-0..*(1對多的關(guān)系)。被觀察者通過集合管理觀察者,并且有三個方法:attach()綁定(add()加入集合) detached()解綁(remove()移除集合) notifiyObeserver()通知所有的觀察者(遍歷集合調(diào)用updata()方法)。
明白了關(guān)系圖那么我們通過代碼來實際運用下加深理解:
/**
* 觀察者
*/
public interface Observer {
void upData(String state);
}
首先我們創(chuàng)建一個觀察者,他只用一個方法upData(String state);更新狀態(tài)。我們在創(chuàng)建兩個類來繼承它。
public class TomObserver implements Observer{
@Override
public void upData(String state) {
/*
* 在這里我們根據(jù)接受到state做相應(yīng)的處理
*/
System.out.println("我是Tom 我在"+state);
}
}
public class JackObserver implements Observer{
@Override
public void upData(String state) {
/*
* 在這里我們根據(jù)接受到state做相應(yīng)的處理
*/
System.out.println("我是Jack 我在"+state);
}
}
在這里我們創(chuàng)建2個觀察者子類Tom和Jack。實現(xiàn)upData()并根據(jù)介紹到的state做相應(yīng)的處理,這里我們只是簡單的打印接到信息。
觀察者創(chuàng)建完成我們在創(chuàng)建被觀察者(Subject/Observable)。
/**
*被觀察者
*/
public abstract class Observable {
List<Observer> list=new ArrayList<>();
/*
* 綁定觀察者
*/
public void attach(Observer observer){
list.add(observer);
System.out.println("綁定觀察者"+observer.getClass().getSimpleName());
}
/*
* 解綁觀察者
*/
public void detach(Observer observer){
list.remove(observer);
System.out.println("解綁被觀察者"+observer.getClass().getSimpleName());
}
/*
* 通知所有觀察者
*/
public void notifyObservers(String state){
for (Observer observer : list) {
observer.upData(state);
}
}
}
這段代碼也很容易理解,就是和上面我們的關(guān)系圖一樣被觀察者通過集合管理觀察者。通過綁定添加,解綁移除,notifyObservers()通知所有觀察者。我們在創(chuàng)建一個他的子類。
public class MessageOberver extends Observable{
public void change(String state){
notifyObservers(state);
}
}
創(chuàng)建子類的,其實它就做了一件事就是調(diào)用父類的notifyObservers()方法。
好了?,F(xiàn)在所有的準(zhǔn)備工作我們已經(jīng)做好了讓我們來實際操作一下,到底是怎么運作的。
public class Test {
public static void main(String[] args) {
Observer jObserver=new JackObserver();
Observer tObserver=new TomObserver();
MessageOberver oberver=new MessageOberver();
oberver.attach(jObserver);
oberver.attach(tObserver);
oberver.change("打籃球");
oberver.detach(tObserver);
oberver.change("跑步");
}
}
這段代碼我們先創(chuàng)建2個Observer(觀察者)實例,再創(chuàng)建MessageOberver(被觀察者)通過attach()綁定,當(dāng)我們被觀察者(再創(chuàng)建MessageOberver),狀態(tài)改變("打籃球")看看會發(fā)生什么?
綁定觀察者JackObserver
綁定觀察者TomObserver
我是Jack 我正在打籃球
我是Tom 我正在打籃球
解綁被觀察者TomObserver
我是Jack 我正在跑步
可以看到當(dāng)我們的被觀察者狀態(tài)改變要去打籃球的時候,所有他的觀察者(也就是attach()綁定的對象)都能接到信息,當(dāng)我們解綁的后解綁的觀察者就不能在接到信息了。這就是我們的觀察者模式。其實這么看來還是挺簡單的。
在理解了觀察者模式后我們在回到文章開始的時候提到的android中用的觀察者模式比如點擊事件,放到我們寫的例子中我們應(yīng)該怎么去理解呢?
public class Test {
public static void main(String[] args) {
Observer jObserver=new JackObserver();
Observer tObserver=new TomObserver();
MessageOberver oberver=new MessageOberver();
/*
* oberver相當(dāng)于Button
* attach相當(dāng)與setOnclickListener
* jObserver相當(dāng)于 OnclickListener
* change方法就是我們在監(jiān)聽中對應(yīng)的要做的事情(這里我們是調(diào)用notifyObservers(),
* 它的內(nèi)部是調(diào)用每個oberver的updata方法 我們可以在updata方法中做不同的處理)
*/
oberver.attach(jObserver);
oberver.attach(tObserver);
oberver.change("打籃球");
oberver.detach(tObserver);
oberver.change("跑步");
}
}
看了我的注釋在結(jié)合平時我們寫的代碼是不是有一種不約而同的感覺呢。那么在實際開發(fā)中我們又在那里用到觀察者模式呢?簡單的例子。其實在實際項目中我們想讓多個界面監(jiān)聽一個對象的狀態(tài)變化時我們就可以用到觀察者模式。比如常見的下載應(yīng)用我隨便找的兩個截圖


這是我們常見手機應(yīng)用軟件的截圖這是兩個不同的頁面,2個頁面下載進(jìn)度同步,其實我們就可以使用觀察者模式,下載任務(wù)為被觀察者頁面(Activity或者Fragment)為觀察者(實現(xiàn)接口,參數(shù)將String state 該改成DownInfo info下載任務(wù))那么當(dāng)下載進(jìn)度改變時我們實時跟新狀態(tài),那么兩個頁面的進(jìn)度同步啦,比如音樂播放進(jìn)度等根據(jù)業(yè)務(wù)要求觀察者設(shè)計模式有時會幫助我們解決不少場景需要。
結(jié)語
這篇文章主要是講解什么觀察者模式,雖然本文是Rxjava小白入門,但是講下觀察者模式還是有必要的。雖然網(wǎng)上也有很多講解,有的講的太深,有的講的太多,并不是他們說的不好,而是身為小白的我去讀太深的東西讓我難以記住和理解,希望這篇文對你有所幫助。下篇文章我會簡單講解下java中的觀察者模式和Rxjava的簡單使用。