你要作一個todo app,有一個Activity裏面有一個ListView顯示你全部的task
,你的數據存儲在服務器。假設你沒采用任何的軟件架構(MVC、MVP、MVVM等等),每次app打開的時候,你從服務器把數據load下來,load完了之後,經過callback把數據傳給Activity,而後顯示到listview裏面。代碼結構大概是這個樣子java
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(List<Task> tasks) { updateTaskList(tasks); } }); model.loadTasks(); } private void updateTaskList(List<Task> 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<Task> tasks); } }
在這裏,當TaskModel load完了task之後,你用的是callback來通知Activity,task已經load好了。這種callback的方式是java裏面很是傳統的方式,尤爲是涉及到異步的時候。這種方式雖然能work,但倒是很是麻煩,也很是醜陋的方式。
首先,你要定義Callback接口,而後在用的地方實現這個接口。
再次,你要在你的model裏面申明一個callback的成員變量,在用的時候,還要判斷一下成員變量是否是空的。固然你能夠用NullObject 模式,但這也須要額外的工做。
最後,當你發現定義的callback接口要變的時候,你要改動的地方可能很是大,由於你可能有不少的地方實現了這個接口,這是很是煩人也是很是容易出錯的工做。
這一來二去,當你的model比較多的時候,你會變得很是煩,這徹底就是體力勞動啊!
那有沒有更好地方式來解決這個問題呢?你可能會想到是Handler
或者是BroadcastReceiver
,然而他們也不是很好用的東西,都要定義一些東西,判斷message,判斷action,傳遞一些引用等等。git
這裏介紹一個library叫Otto,這是Square這個公司的一個開源項目,它是一個EventBus的library。簡單的來講,它相似於定義了一套Observer Pattern的便捷的實現方式。你在某一個地方使用@Subscribe
表示你要處理某一種事件,在某個地方用post發佈這一種事件,那麼前面用@Subscribe
修飾的方法就能夠自動獲得調用。不用定義接口,不用實現接口,一切都很直觀,如你所願。
關於Otto的使用官網說的很是清楚。
在這裏簡單地用Otto重寫一下上面的代碼,讓你們感覺一下。github
public class TasksActivity extends Activity { private ListView mListView; public void onCreate() { OttoHelper.register(this); //對於Subscriber來講,register和unregister是有必要的 } //... private void loadTasks() { new TaskModel().loadTasks(); } // 用@Subscribe 來表示用這個方法處理某種事件,這種事件就是你的方法的參數。 // 此外,public void是必須的,方法名能夠本身隨便取 @Subscribe public void onTaskLoaded(TaskLoadedEvent event) { List<Task> tasks = 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 通常是用做單例的,因此有一個helper會很方便 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<Task> tasks; public TaskLoadedEvent(List<Task> tasks) { this.tasks = tasks; } } public class TaskLoadErrorEvent { //final field errorMsg and code, and construction, just like TaskLoadedEvent }
須要說明的是,這裏只處理了一種事件(load task),因此Otto的優點還不是很明顯,然而你依然能夠明顯感覺到的是,TaskModel
和TasksActivity
之間的耦合性更弱了。他們之間除了都用了Task
和OttoHelper
這兩個類以及用來傳遞事件的Event類,再沒有其餘共同的東西。服務器
當事件多了起來,Otto的優點就會很是明顯,增長的只是Event這些輕量級的POJO而已。
很是須要的一點是,最好每一種事件都使用特殊的Event類,千萬不要使用常見的類,好比String等等,更不要使用Object,由於Otto判斷Subscribe方法所處理的事件是經過方法的參數來判斷的。只要 instance of
爲true,那麼這個方法就會獲得調用。舉個例子,在上面的TasksActivity裏,假如你有另一個Subscribe函數,它的參數是Object:架構
public class TasksActivity extends Activity { //... @Subscribe public void onTaskLoaded(TaskLoadedEvent event) { List<Task> tasks = 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
就會獲得調用,好比task load成功了,你post了TaskLoadedEvent,那麼除了onTaskLoaded
會獲得調用的以外,onSomeEvent
也會獲得調用,這極可能不是你想要的。
我曾經就犯了這個愚蠢的錯誤,更搞笑的是,我在onSomeEvent
裏面直接finish activity了,結果每一次別的事件過來,Activity就退出了,我覺得程序奔潰了,找了半天都找不出緣由,由於你正常finish activity是不會有error log的,最後終於懷疑到它頭上來,而後才解決了這個問題。
把 compile 'com.squareup:otto:1.3.7’
加到你的dependencies裏面,試用如下,我敢打賭,你不再會定義callback了,Callbacks should be dead!.
固然,除了Otto,還有其餘的一些library,好比greenbot開源的EventBus,功能貌似比Otto更強,可是我我的選擇Otto,由於信仰Square,哈哈。。app
這個例子只是用來講明Otto相對於callback的好處,對於一個正常的相似於上面的例子的app,這篇文章中提到的model和activity的交互方式並非最好的方式,有其餘更好的好比Functional Reactive Programming(RxJava)。同時,咱們應該使用MVP模式,把Activity當作View,而不是直接在裏面調用model。異步
若是有任何意見或建議,或者是發現文中有任何問題歡迎留言!函數