摘要:他們之間除了都用了和這兩個(gè)類以及用來傳遞事件的類,再?zèng)]有其他共同的東西。當(dāng)事件多了起來,的優(yōu)勢就會(huì)非常明顯,增加的只是這些輕量級的而已。
傳統(tǒng)的方式
你要做一個(gè)todo app,有一個(gè)Activity里面有一個(gè)ListView顯示你所有的task,你的數(shù)據(jù)存儲(chǔ)在服務(wù)器。假設(shè)你沒采用任何的軟件架構(gòu)(MVC、MVP、MVVM等等),每次app打開的時(shí)候,你從服務(wù)器把數(shù)據(jù)load下來,load完了以后,通過callback把數(shù)據(jù)傳給Activity,然后顯示到listview里面。代碼結(jié)構(gòu)大概是這個(gè)樣子
public class TasksActivity extends Activity { private ListView mListView; //... private void loadTasks() { TaskModel model = new TaskModel(); model.setTaskCallback(new TaskCallback() { public void onError(String msg, int code) { // handle error } public void onSucceed(Listtasks) { updateTaskList(tasks); } }); model.loadTasks(); } private void updateTaskList(List tasks) { //Update the task list view } // other code } public class Task { // title, label, ..., and their getters and setters. } public class TaskModel { public void loadTasks() { //load tasks from server, when result returns, check if callback is not null and call callback } private TaskCallback mTaskCallback; public void setTaskCallback(TaskCallback callback) { this.mTaskCallback = callback; } public static interface TaskCallback { public void onError(String errorMsg, int code); public void onSucceed(List tasks); } }
在這里,當(dāng)TaskModel load完了task以后,你用的是callback來通知Activity,task已經(jīng)load好了。這種callback的方式是java里面非常傳統(tǒng)的方式,尤其是涉及到異步的時(shí)候。這種方式雖然能work,但卻是非常麻煩,也非常丑陋的方式。
首先,你要定義Callback接口,然后在用的地方實(shí)現(xiàn)這個(gè)接口。
再次,你要在你的model里面申明一個(gè)callback的成員變量,在用的時(shí)候,還要判斷一下成員變量是不是空的。當(dāng)然你可以用NullObject 模式,但這也需要額外的工作。
最后,當(dāng)你發(fā)現(xiàn)定義的callback接口要變的時(shí)候,你要改動(dòng)的地方可能非常大,因?yàn)槟憧赡苡泻芏嗟牡胤綄?shí)現(xiàn)了這個(gè)接口,這是非常煩人也是非常容易出錯(cuò)的工作。
這一來二去,當(dāng)你的model比較多的時(shí)候,你會(huì)變得非常煩,這完全就是體力勞動(dòng)??!
那有沒有更好地方式來解決這個(gè)問題呢?你可能會(huì)想到是Handler或者是BroadcastReceiver,然而他們也不是很好用的東西,都要定義一些東西,判斷message,判斷action,傳遞一些引用等等。
這里介紹一個(gè)library叫Otto,這是Square這個(gè)公司的一個(gè)開源項(xiàng)目,它是一個(gè)EventBus的library。簡單的來說,它類似于定義了一套Observer Pattern的便捷的實(shí)現(xiàn)方式。你在某一個(gè)地方使用@Subscribe 表示你要處理某一種事件,在某個(gè)地方用post發(fā)布這一種事件,那么前面用@Subscribe修飾的方法就可以自動(dòng)得到調(diào)用。不用定義接口,不用實(shí)現(xiàn)接口,一切都很直觀,如你所愿。
關(guān)于Otto的使用官網(wǎng)說的非常清楚。
在這里簡單地用Otto重寫一下上面的代碼,讓大家感受一下。
public class TasksActivity extends Activity { private ListView mListView; public void onCreate() { OttoHelper.register(this); //對于Subscriber來說,register和unregister是有必要的 } //... private void loadTasks() { new TaskModel().loadTasks(); } // 用@Subscribe 來表示用這個(gè)方法處理某種事件,這種事件就是你的方法的參數(shù)。 // 此外,public void是必須的,方法名可以自己隨便取 @Subscribe public void onTaskLoaded(TaskLoadedEvent event) { Listtasks = event.tasks; // Update the task list view } @Subscribe public void onTaskLoadError(TaskLoadErrorEvent event) { //handler error } public void onDestroy() { OttoHelper.unregister(this) } } public class Task { // title, label, ..., and their getters and setters. } public class TaskModel { public void loadTasks() { // Load task from server OttoHelper.post(new TaskLoadedEvent(tasks)); //If load succeed OttoHelper.post(new TaskLoadErrorEvent(errorMsg, code); //If load error } } //Bus 一般是用作單例的,所以有一個(gè)helper會(huì)很方便 public class OttoHelper { private static final Bus sBusInstance = new Bus(); public void static register(Object obj) { sBusInstance.register(obj); } public void static unregister(Object obj) { sBusInstance.register(obj); } public static void post(Object event) { sBusInstance.post(event); } } public class TaskLoadedEvent { public final List tasks; public TaskLoadedEvent(List tasks) { this.tasks = tasks; } } public class TaskLoadErrorEvent { //final field errorMsg and code, and construction, just like TaskLoadedEvent }
需要說明的是,這里只處理了一種事件(load task),所以O(shè)tto的優(yōu)勢還不是很明顯,然而你依然可以明顯感受到的是,TaskModel和TasksActivity之間的耦合性更弱了。他們之間除了都用了Task和OttoHelper這兩個(gè)類以及用來傳遞事件的Event類,再?zèng)]有其他共同的東西。
當(dāng)事件多了起來,Otto的優(yōu)勢就會(huì)非常明顯,增加的只是Event這些輕量級的POJO而已。
非常需要的一點(diǎn)是,最好每一種事件都使用特殊的Event類,千萬不要使用常見的類,比如String等等,更不要使用Object,因?yàn)镺tto判斷Subscribe方法所處理的事件是通過方法的參數(shù)來判斷的。只要 instance of為true,那么這個(gè)方法就會(huì)得到調(diào)用。舉個(gè)例子,在上面的TasksActivity里,假如你有另外一個(gè)Subscribe函數(shù),它的參數(shù)是Object:
public class TasksActivity extends Activity { //... @Subscribe public void onTaskLoaded(TaskLoadedEvent event) { Listtasks = event.tasks; // Update the task list view } @Subscribe public void onTaskLoadError(TaskLoadErrorEvent event) { //handler error } @Subscribe public void onSomeEvent(Object event) { //handle some-event } }
在上面的事件中,bus post的任何事件,主要TasksActivity沒有unregister,那么onSomeEvent就會(huì)得到調(diào)用,比如task load成功了,你post了TaskLoadedEvent,那么除了onTaskLoaded會(huì)得到調(diào)用的之外,onSomeEvent也會(huì)得到調(diào)用,這很可能不是你想要的。
我曾經(jīng)就犯了這個(gè)愚蠢的錯(cuò)誤,更搞笑的是,我在onSomeEvent里面直接finish activity了,結(jié)果每一次別的事件過來,Activity就退出了,我以為程序奔潰了,找了半天都找不出原因,因?yàn)槟阏inish activity是不會(huì)有error log的,最后終于懷疑到它頭上來,然后才解決了這個(gè)問題。
把 compile "com.squareup:otto:1.3.7’加到你的dependencies里面,試用以下,我敢打賭,你再也不會(huì)定義callback了,Callbacks should be dead!.
當(dāng)然,除了Otto,還有其他的一些library,比如greenbot開源的EventBus,功能貌似比Otto更強(qiáng),但是我個(gè)人選擇Otto,因?yàn)樾叛鯯quare,哈哈。。
這個(gè)例子只是用來說明Otto相對于callback的好處,對于一個(gè)正常的類似于上面的例子的app,這篇文章中提到的model和activity的交互方式并不是最好的方式,有其他更好的比如Functional Reactive Programming(RxJava)。同時(shí),我們應(yīng)該使用MVP模式,把Activity當(dāng)做View,而不是直接在里面調(diào)用model。
如果有任何意見或建議,或者是發(fā)現(xiàn)文中有任何問題歡迎留言!
作者 小創(chuàng) 更多文章 | Github | 公眾號
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/64357.html
摘要:最佳解析最佳解析最佳解析是一個(gè)依賴注入框架,由谷歌開發(fā),最早的版本由公司開發(fā)。在對的介紹中指出,即,這里的即數(shù)據(jù)結(jié)構(gòu)中的有向無環(huán)圖。也就是說,是一個(gè)基于有向無環(huán)圖結(jié)構(gòu)的依賴注入庫,因此的使用過程中不能出現(xiàn)循環(huán)依賴。 在開發(fā)過程中使用過很多優(yōu)秀框架,比如網(wǎng)絡(luò)的okhttp,圖片的Fresco,注入的Gagger2等,都是非常優(yōu)秀的框架。 所以今天在此介紹下至今本人知道的一些比較流行主流且...
摘要:它有發(fā)布者,訂閱者這兩個(gè)主要對象。的最佳實(shí)踐就是通過反射犧牲了微小的性能,同時(shí)極大的降低了程序的耦合度。官網(wǎng)和應(yīng)用場景框架的主要功能是幫助我們來降低多個(gè)組件通信之間的耦合度的解耦。 前兩天在公眾號里發(fā)了一篇有關(guān)EventBus的文章《玩轉(zhuǎn)EventBus,詳解其使用》,有讀者和開發(fā)者反饋說沒有OTTO好用。確實(shí)是,各有優(yōu)缺點(diǎn)吧,那今天就有必要再講一下Otto事件框架。 OTTO是Squ...
閱讀 3528·2021-09-22 15:50
閱讀 3233·2019-08-30 15:54
閱讀 2748·2019-08-30 14:12
閱讀 3058·2019-08-30 11:22
閱讀 2079·2019-08-29 11:16
閱讀 3574·2019-08-26 13:43
閱讀 1192·2019-08-23 18:33
閱讀 920·2019-08-23 18:32