Android學習系列(43)--使用事件總線框架EventBus和Otto

事件總線框架

針對事件提供統一訂閱,發佈以達到組件間通訊的解決方案。java

原理

觀察者模式。android

EventBus和Otto

先看EventBus的官方定義:git

Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.

再看Otto官方定義:github

Otto is an event bus designed to decouple different parts of your application while still allowing them to communicate efficiently.

總之,簡化android應用內組件通訊。設計模式

對比BroadcastReceiver

在工做上,我在兩個場景下分別使用過Otto和EventBus,一個是下載管理器通知各個相關的Activity當前的進度,一個是設置應用壁紙。
單從使用上看,EventBus > Otto > BroadcastReceiver(固然BroadcastReceiver做爲系統內置組件,有一些前二者沒有的功能).
EventBus最簡潔,Otto最符合Guava EventBus的設計思路, BroadcastReceiver最難使用。
我我的的第一選擇是EventBus。app

實例:「設置壁紙」

兩大的框架的基本使用都很是簡單:
EventBus的基本使用官方參考:https://github.com/greenrobot/EventBus
Otto的基本使用官方參考:http://square.github.io/otto/框架

EventBus實現篇

EventBus規定onEvent方法固定做爲訂閱者接受事件的方法,應該是參考了「約定優於配置」思想。ide

  1. 定義EventModel,做爲組件間通訊傳遞數據的載體
public class WallpaperEvent {

    private Drawable wallpaper;

    public WallpaperEvent(Drawable wallpaper) {
        this.wallpaper = wallpaper;
    }

    public Drawable getWallpaper() {
        return wallpaper;
    }

    public void setWallpaper(Drawable wallpaper) {
        this.wallpaper = wallpaper;
    }
}
  1. 定義訂閱者,最重要的是onEvent方法
public class BaseActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        EventBus.getDefault().register(this);
        initWallpaper();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    public void onEvent(WallpaperEvent wallpaperEvent) {
        // AppConfig.sWallpaperDrawable as a global static var
        AppConfig.sWallpaperDrawable = wallpaperEvent.getWallpaper();
        initWallpaper();
    }

    private void initWallpaper() {
        // support custom setting the wallpaper
        // 根據AppConfig.sWallpaperDrawable,默認值等設置當前Activity的背景壁紙
        // ...
    }
}
  1. 經過post()方法在任何地方發佈消息(壁紙,準確的說是WallpaperEvent)給全部的BaseActivity子類,舉個例子:
private void downloadWallpapper(String src) {
        ImageLoader.getInstance().loadImage(src, new SimpleImageLoadingListener() {
            @Override
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {

                BitmapDrawable wallpaper = new BitmapDrawable(loadedImage);
                // presist the image url for cache
                saveWallpaper(imageUri);

                // notify all base activity to update wallpaper
                EventBus.getDefault().post(new WallpaperEvent(wallpaper));


                Toast.makeText(WallpapeEventBusrActivity.this,
                        R.string.download_wallpaper_success,
                        Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                Toast.makeText(WallpaperActivity.this,
                        R.string.download_wallpaper_fail,
                        Toast.LENGTH_SHORT).show();
            }
        });
    }

重點就是這句:post

// 在任何地方調用下面的方法,便可動態全局實現壁紙設置功能
EventBus.getDefault().post(new WallpaperEvent(wallpaper));

Otto實現篇

這裏要注意幾點點:
(1)Otto使用註解定義訂閱/發佈者的角色,@Subscribe爲訂閱者,@Produce爲發佈者,方法名稱就能夠自定義了。
(2)Otto爲了性能,代碼意圖清晰,@Subscribe,@Produce方法必須定義在直接的做用類上,而不能定義在基類而被繼承。
(3)和EventBus不一樣的是,發佈者也須要register和unregister,而EventBus的發佈者是不須要的。性能

  1. 定義EventModel,做爲組件間通訊傳遞數據的載體
public class WallpaperEvent {

    private Drawable wallpaper;

    public WallpaperEvent(Drawable wallpaper) {
        this.wallpaper = wallpaper;
    }

    public Drawable getWallpaper() {
        return wallpaper;
    }

    public void setWallpaper(Drawable wallpaper) {
        this.wallpaper = wallpaper;
    }
}
  1. 避免浪費,相對於EventBus.getDefault(), Otto須要本身實現單例。
public class AppConfig {

    private static final Bus BUS = new Bus();

    public static Bus getInstance() {
        return BUS;
    }
}
  1. 定義訂閱者,在接受事件的方法加上修飾符@Subscribe
public class BaseActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        AppConfig.getBusInstance().register(this);
        initWallpaper();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        AppConfig.getBusInstance().unregister(this);
    }

    public void onOttoEvent(WallpaperEvent wallpaperEvent) {
        AppConfig.sWallpaperDrawable = wallpaperEvent.getWallpaper();
        initWallpaper();
    }

    private void initWallpaper() {
        // support custom setting the wallpaper
        // 根據AppConfig.sWallpaperDrawable,默認值等設置當前Activity的背景壁紙
        // ...
    }
}
  1. 定義發佈者,經過post()方法在任何地方發佈消息了
public class WallpaperActivity extends BaseActivity {

    private Drawable wallpaperDrawable;

    //這裏同時也要更新本身壁紙,因此顯示定義@Subscribe的方法
    @Subscribe
    public void onWallpaperUpdate(WallpaperEvent wallpaperEvent) {
        super.onWallpaperUpdate(wallpaperEvent);
    }

    @Produce
    public WallpaperEvent publishWallPaper() {
        return new WallpaperEvent(wallpaperDrawable);
    }

    private void downloadWallpapper(String src) {
        //...
        //通知全部@Subscribe匹配WallpaperEvent參數的方法執行
        AppConfig.getBusInstance().post(publishWallPaper());
        //...
    }
}

小結

  1. 使用設計模式的思想解決問題,這纔是設計模式的真正價值。
  2. 這兩個android事件總線框架提供了一種更靈活更強大而又更加完美解耦的解決方案,在不少場合,從開發效率,執行性能和設計思路上都要優於BroadcastReceiver,值得學習使用。
相關文章
相關標籤/搜索