前言:Otto事件匯流排 -- 組件之間通訊架構對於之前的情況activity之間或者fragment之間等跳轉傳值一般都是用bundle、intent等,從activityA --- activityB用startActivity,用startActivityForResult()可以接受後者回到前者的參數並且可做一些更新UI等操作。這樣一來就要判斷從A中哪一個按鈕跳轉到了B,就要設定唯一標識定義什麼FRIST=1,FFFFF=2等。Otto事件匯流排解決了這個問題,只要在訂閱事件,接收方接受訂閱,傳實值型別為唯一標示。這樣子只要在觸發了post後,接受方就會執行指定方法,就算不返回到A介面也是可以執行的。使用Otto事件匯流排架構的原因
- 一般情況下,在Android中的Activity與Activity之間值的傳遞,我們通過Intent的方式;
- Activity與Fragment之間我們通過setArguments,值回調我們是在Fragment中的onAttach()介面方式實現;
- Activity與service之間,我們通常會使用binder機制,但是binder機制實際上使用的也是介面回調的方式;
- 在一些比較複雜的情況,比如Activity嵌套多個Fragment頁面的時候,如果一個頁面的值發生了改變,其他的頁面也要跟著發生資料的更新操作,這樣我們會頻繁的使用介面回調的方式,這種方式的耦合性太高。
Otto事件的模式
對於一個如此方便的架構,Java模式的加入是必不可少的,無論是Rxjava(觀察者模式擴充)還是EventBus都有觀察者模式,所以中間講解該模式。
一、簡單使用
@Subscribe:這個在調用了register後有效,表示訂閱了一個事件,並且方法的用 public 修飾的.方法名可以隨意取,重點是參數,它是根據你的參數進行判斷
@Produce註解告訴Bus該函數是一個事件產生者,產生的事件類型為該函數的傳回值。
1-1:添加依賴
dependencies { compile 'com.squareup:otto:1.3.8'}或者//otto事件匯流排 compile 'com.squareup:otto:+'1-2:訂閱和取消訂閱
bus.register(this);bus.unregister(this);發布:bus.post(new MessageEvent());註解@Subscribe:這個在調用了register後有效,表示訂閱了一個事件,並且方法的用 public 修飾的.方法名可以隨意取,重點是參數,它是根據你的參數進行判斷@Produce註解告訴Bus該函數是一個事件產生者,產生的事件類型為該函數的傳回值。最後,proguard 需要做一些額外處理,防止混淆:-keepattributes *Annotation*-keepclassmembers class ** { @com.squareup.otto.Subscribe public *; @com.squareup.otto.Produce public *;}1-3:otto推薦使用單例模式,保證只有一個執行個體
public class BusProvider extends Bus { /** * 通過單例模式返回唯一的bus對象,而且重寫父類的post方法,通過handler實現任意線程可以調用 */ private Handler mHandler = new Handler(Looper.getMainLooper()); private static Bus bus = new BusProvider(); private BusProvider(){ } public static Bus getInstance(){ return bus; } @Override public void post(final Object event) { if (Looper.myLooper() == Looper.getMainLooper()) { super.post(event); }else { mHandler.post(new Runnable() { @Override public void run() { BusProvider.super.post(event); } }); } }}1-4:調用 A-->B@SubscribeactivityA:
/** * Created by 劉志通 on 2018/7/4. */public class OttoTestOne extends AppCompatActivity { private Bus bus; private Button button,button2; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ottotwo_layout); //訂閱 bus = BusProvider.getInstance(); bus.register(this); button = findViewById(R.id.id_two); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(OttoTestOne.this,OttoTestTwo.class); startActivity(intent); } }); }//註解接收String類型 @Subscribe public void setText(String textstring) { button.setText(textstring); Log.e("檢測1",textstring+""); }//接收bean類型 @Subscribe public void setText2(EditBean textstring) { button2.setText(textstring.getEdit1()+""+textstring.getEdit2()); Log.e("檢測2", textstring.getEdit1()+""+textstring.getEdit2()); } /** * 取消訂閱 * */ @Override protected void onDestroy() { BusProvider.getInstance().unregister(this); super.onDestroy(); }}
activityB
/** * Created by 劉志通 on 2018/7/4. */public class OttoTestTwo extends AppCompatActivity { private Bus bus; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //擷取執行個體 bus = BusProvider.getInstance(); //註冊 bus.register(this); setContentView(R.layout.ottoone_layout); Button button=findViewById(R.id.id_btn); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /*發送,這裡發送的是bean,也可以直接發送String類型的資料,接收則是A中String類型的接收。*/ EditBean editBean=new EditBean(); editBean.setEdit1("ni"); editBean.setEdit2(" hao"); editBean.setTotal(" ma"); bus.post(editBean); } }); }}@Produce
只要有activity或者fragment跳轉到該頁面後,事件就會自動產生,然後在訂閱處(誰訂閱誰改變)更新一些資料。
//擷取執行個體 bus = BusProvider.getInstance(); //註冊 bus.register(this); setContentView(R.layout.ottothird_layout); } @Produce public EditBean providerEvent(){ EditBean eventData = new EditBean(); eventData.setEdit1("hello world"); return eventData; } @Override protected void onDestroy() { super.onDestroy(); bus.unregister(this); }註:A->B中 @Produce模式則是在A中發起事件,也就是所謂的事件產生者,當從A跳轉到B後,如果B中有對EditBean有操作的話,就直接觸及到A的@Produce方法,並更新一些資料,這和Post比起來,有點簡單,因為你都不用再做任何操作,前一個介面就已經更新了,但Post可以控制何時發起事件,點擊按鈕後或者網路請求成功後直接bus.post(" ... ");二、觀察者模式前言觀察者模式(有時又被稱為模型-視圖(View)模式、源-收聽者(Listener)模式或從屬者模式)是軟體設計模式的一種。在此種模式中,一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。需要注意:實現觀察者模式的時候要注意,觀察者和被觀察對象之間的互動關係不能體現成類之間的直接調用,否則就將使觀察者和被觀察對象之間緊密的耦合起來,從根本上違反物件導向的設計的原則。無論是觀察者“觀察”觀察對象,還是被觀察者將自己的改變“通知”觀察者,都不應該直接調用。觀察者(Observer)將自己註冊到被觀察對象(Subject)中,被觀察對象將觀察者存放在一個容器(Container)裡。被觀察被觀察對象發生了某種變化,從容器中得到所有註冊過的觀察者,將變化通知觀察者。撤銷觀察觀察者告訴被觀察者要撤銷觀察,被觀察者從容器中將觀察者去除。觀察者將自己註冊到被觀察者的容器中時,被觀察者不應該過問觀察者的具體類型,而是應該使用觀察者的介面。這樣的優點是:假定程式中還有別的觀察者,那麼只要這個觀察者也是相同的介面實現即可。一個被觀察者可以對應多個觀察者,當被觀察者發生變化的時候,他可以將訊息一一通知給所有的觀察者。基於介面,而不是具體的實現——這一點為程式提供了更大的靈活性。
舉例子:
這裡建立一個抽象觀察者(Observer)和一個被觀察者(Subject),然後繼承抽象觀察者,觀察者們通過觀察被觀察者(Subject)來改變自己。
建立類:
- 抽象觀察者(Observer)
- 被觀察者(Subject)
2-1:被觀察者Subject.java
public class Subject { private List<Observer> observers = new ArrayList<Observer>(); private Observer observer; private int state; //變更情況 public int getState() { return state; } public void setState(int state) { this.state = state; } //綁定 public void binding(Observer observer) { observers.add(observer); } /** * unbinding(登出觀察者,有時候在未擷取到執行個體使用) **/ public void unbinding(Observer cls) { if (cls == null) throw new NullPointerException(); observers.remove(cls); } //通知 public void notifyAllObservers() { for (Observer observer : observers) { observer.update(); } }}
這裡需要注意的是如果是常規集合是不能直接用remove的,要如下轉換再行刪除。
Iterator<Observer> iterator = observers.iterator();
2-2:觀察者(Observer)
/** * 觀察者 * */public abstract class Observer { protected Subject subject; public abstract void update();}2-3:繼承Observer
需要注意的是,我這裡建立了3個如下類,只粘貼出一個,分別是FirstObserver,SecondObserver,ThirdObserver。
public class FirstObserver extends Observer { public FirstObserver(Subject subject) { this.subject = subject; subject.binding(this);//綁定 } @Override public void update() { //用來更新資料 System.out.println("我是第一個觀察者:"+subject.getState()); }}
2-4:測試
在主方法main中 這裡是在每個子類的構造方法中加入了綁定,所以,只要建立對象就已經綁定了,無序再次綁定,當然也是可以解除綁定的。
//載入被觀察者 Subject subject = new Subject(); //載入觀察者 FirstObserver firstObserver = new FirstObserver(subject); SecondObserver secondObserver = new SecondObserver(subject); ThirdObserver thirdObserver = new ThirdObserver(subject); subject.setState(2); subject.notifyAllObservers();
解除綁定
subject.unbinding(secondObserver); subject.setState(3); subject.notifyAllObservers();