事件总线框架

针对事件提供统一订阅,发布以达到组件间通信的解决方案。

原理

观察者模式。

EventBus和Otto

先看EventBus的官方定义:

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

再看Otto官方定义:

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。

实例:“设置壁纸”

两大的框架的基本使用都非常简单:

EventBus的基本使用官方参考:https://github.com/greenrobot/EventBus

Otto的基本使用官方参考:http://square.github.io/otto/

EventBus实现篇

EventBus规定onEvent方法固定作为订阅者接受事件的方法,应该是参考了“约定优于配置”思想。

  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();
}
});
}

重点就是这句:

// 在任何地方调用下面的方法,即可动态全局实现壁纸设置功能
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,值得学习使用。

Android学习系列(43)--使用事件总线框架EventBus和Otto的更多相关文章

  1. Android学习系列(23)--App主界面实现

    在上篇文章<Android学习系列(22)--App主界面比较>中我们浅略的分析了几个主界面布局,选了一个最大众化的经典布局.今天我们就这个经典布局,用代码具体的实现它. 1.预览图先看下 ...

  2. Android学习系列(17)--App列表之圆角ListView(续)

    http://www.cnblogs.com/qianxudetianxia/archive/2011/09/19/2068760.html   本来这篇文章想并到上篇Android学习系列(16)- ...

  3. Android学习系列--App列表之拖拽ListView(上)

    研究了很久的拖拽ListView的实现,受益良多,特此与尔共飨.      鉴于这部分内容网上的资料少而简陋,而具体的实现过程或许对大家才有帮助,为了详尽而不失真,我们一步一步分析,分成两篇文章. 一 ...

  4. Android学习系列(7)--App轮询服务器消息

    这篇文章是android开发人员的必备知识. 1.轮询服务器     一般的应用,定时通知消息可以采用轮询的方法从服务器拿取消息,当然实时消息通知的话,建议采用推送服务.    其中需要注意轮询的频率 ...

  5. Android学习系列(15)--App列表之游标ListView(索引ListView)

    游标ListView,提供索引标签,使用户能够快速定位列表项.      也可以叫索引ListView,有的人称也为Tweaked ListView,可能更形象些吧.      一看图啥都懂了: 1. ...

  6. [置顶] Android学习系列-Android中解析xml(7)

    Android学习系列-Android中解析xml(7) 一,概述 1,一个是DOM,它是生成一个树,有了树以后你搜索.查找都可以做. 2,另一种是基于流的,就是解析器从头到尾解析一遍xml文件.   ...

  7. Android开发事件总线之EventBus运用和框架原理深入理解

    [Android]事件总线之EventBus的使用背景 在我们的android项目开发过程中,经常会有各个组件如activity,fragment和service之间,各个线程之间的通信需求:项目中用 ...

  8. Otto事件总线框架的使用

    Otto是一个在Android中的事件总线框架,它是square的一个开源框架,具体介绍点击这里,项目下载点击这里 为什么要使用Otto事件总线: 通常来说在Android中: 1.Activity与 ...

  9. Android学习系列(11)--App列表之拖拽ListView(下)

    接着上篇Android学习系列(10)--App列表之拖拽ListView(上)我们继续实现ListView的拖拽效果. 7.重写onTouchEvent()方法.     在这个方法中我们主要是处理 ...

随机推荐

  1. 【干货】ECS服务器OPENVPN搭建,方便管理所有内网服务器

    [干货]ECS服务器OPENVPN搭建,方便管理所有内网服务器 使用场景 一台有外网的ECS服务器+N台无外网的ECS服务器,使用OPENVPN管理全部的ECS服务器(包括无外网的ECS服务器). 鉴 ...

  2. (转)JAVA AJAX教程第二章-JAVASCRIPT基础知识

    开篇:JAVASCRIPT是AJAX技术中不可或缺的一部分,所以想学好AJAX以及现在流行的AJAX框架,学好JAVASCRIPT是最重要的.这章我给大家整理了一些JAVASCRIPT的基础知识.常用 ...

  3. 【hadoop2.6.0】数据丢失问题解决

    想自己走一遍从代码到运行的流程,结果各种错,郁闷啊. 问题① http://localhost:50070/ 里面一进去就告诉我块丢了.... 解决: bin/hadoop fsck -delete ...

  4. 【linux】linux脚本中#!/bin/sh的含义

    来源:百度知道 #! /bin/sh 是指此脚本使用,/bin/sh来解释执行,#!是特殊的表示符,其后面根的是此解释此脚本的shell的路径.

  5. 二、JavaScript语言--JS实践--商城分类导航效果

    商城类导航菜单制作(以京东为例--竖向列表横向伸缩) 可以用两种方式来实现:用CSS实现和用JS实现 方法一:用CSS实现(要点:使用hover) <!DOCTYPE html PUBLIC & ...

  6. 最稳定 性能最好 的 Linux 版本?

    Ubuntu太他妈不稳定了,简直是一坨屎 CentOS.Ubuntu.Debian三个linux比较异同http://blog.csdn.net/educast/article/details/383 ...

  7. hdu 2203:亲和串(水题,串的练习)

    亲和串 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  8. <转>Oracle SQL性能优化

    原文链接:http://www.cnblogs.com/rootq/archive/2008/11/17/1334727.html (1)      选择最有效率的表名顺序(只在基于规则的优化器中有效 ...

  9. 7-14 EXISTS子查询

    EXISTS: 只注重于子查询是否有返回行,如果查有返回行返回结果为值,否则为假 并不使用子查询的结果,仅用于测试子查询是否有返回结果. 语法: IF EXISTS (子查询) BEGIN 语句块 E ...

  10. PHPCMS V9 WAP手机门户域名绑定

    如需要绑定域名为wap.domain.com,作下如操作: 一.把wap.domain.com域名绑定到你的这个网站主机上. 二.在网站后台模块>手机门户域名里面填写“http://wap.do ...