EventBus给android应用开发带来了统一的生产消费设计模式,大大提升了模块解耦能力,但不同模块间任然存在编译依赖,对应更大型的工程,如不同插件(运行依赖)则支持有限,在此基础上,设计了一套全解耦的消息驱动模型,解决了模块的编译依赖。
将EventBus接口分装,做成消息驱动,简化接口
package com.jd.mall.data;
import java.util.HashMap;
import java.util.Map;
import de.greenrobot.event.EventBus;
/**
* Created by zephyrluo on 2015/01/23.
*/
/*
register: ObserverMgr.register(this);
*/
public class ObserverEvent {
private EventBus eb;
private String observerKey;
static Map<string observerevent=""> osi = new HashMap<string observerevent="">();
public ObserverEvent(String s) {
observerKey = s;
eb=EventBus.getDefault();
eb.register(this);
}
/*
@hide
*/
public void onEvent(Object val) {
ObserverMgr.postInner(observerKey, val, ObserverMgr.FIRE_IN_SRC_THREAD);
}
/*
@hide
*/
public void onEventBackgroundThread(Object val) {
ObserverMgr.postInner(observerKey, val, ObserverMgr.FIRE_IN_BG_THREAD);
}
/*
@hide
*/
public void onEventMainThread(Object val) {
ObserverMgr.postInner(observerKey, val, ObserverMgr.FIRE_IN_UI_THREAD);
}
/*
@hide
*/
public void onEventAsync(Object val) {
ObserverMgr.postInner(observerKey, val, ObserverMgr.FIRE_IN_ASYNC);
}
public static void post(String s, Object result) {
ObserverEvent ob = ObserverEvent.obtain(s);
ob.post(result);
}
public static ObserverEvent obtain(String s) {
if(osi.containsValue(s)) return osi.get(s);
ObserverEvent oi = new ObserverEvent(s);
osi.put(s, oi);
return oi;
}
public void post(Object result){
eb.post(result);
}
}
利用annotation特性,进一步简化接口
package com.jd.mall.data;
import android.os.Bundle;
import android.util.Pair;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import de.greenrobot.event.EventBus;
import de.greenrobot.event.ThreadMode;
/**
* Created by luozhifan on 2015/01/13.
*/
public class ObserverMgr {
final public static int FIRE_IN_SRC_THREAD = 1<<0;
final public static int FIRE_IN_UI_THREAD = 1<<1;
final public static int FIRE_IN_BG_THREAD = 1<<2;
final public static int FIRE_IN_ASYNC = 1<<3;
private static HashMap<Pair<String, Integer>, HashSet<Pair<Object, Method>>> obs
= new HashMap<Pair<String, Integer>, HashSet<Pair<Object, Method>>>();
@Retention(RetentionPolicy.RUNTIME)
public static @interface Observer{
String key();
int mode();
}
public static void register(Object subscriber){
for(Method m:subscriber.getClass().getMethods()) {
Observer ob = m.getAnnotation(Observer.class);
if (ob==null) continue;
String key = ob.key();
int fireModes = ob.mode();
for (int i=0; i<4; i++){
int fireMode = 1<<i;
if ((fireMode&fireModes) == 0) continue;
Pair<String, Integer> keyPair = Pair.create(key, fireMode);
if(!obs.containsKey(keyPair)) {
obs.put(keyPair, new HashSet<Pair<Object, Method>>());
}
obs.get(keyPair).add( Pair.create(subscriber, m) );
}
}
}
public static void unregister(Object subscriber){
for(Method m:subscriber.getClass().getMethods()) {
Observer ob = m.getAnnotation(Observer.class);
if (ob==null) continue;
String key = ob.key();
int fireModes = ob.mode();
for (int i=0; i<4; i++) {
int fireMode = 1 << i;
if ((fireMode & fireModes) == 0) continue;
Pair<String, Integer> keyPair = Pair.create(key, fireMode);
obs.get(keyPair).remove(Pair.create(subscriber, m));
}
}
}
public static void unregister(String key){
for (int i=0; i<4; i++) {
int fireMode = 1 << i;
Pair<String, Integer> keyPair = Pair.create(key, fireMode);
obs.remove(keyPair);
}
}
static void postInner(String key, Object event, int mode){
Pair<String, Integer> keyPair = Pair.create(key, mode);
if(!obs.containsKey(keyPair)) return;
for (Pair<Object, Method> cb : obs.get(keyPair)){
try {
cb.second.invoke(cb.first, event);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
使用例子,消息驱动处理如下: @ObserverMgr.Observer(key="Preference.test2",
mode=ObserverMgr.FIRE_IN_SRC_THREAD|ObserverMgr.FIRE_IN_UI_THREAD|ObserverMgr.FIRE_IN_BG_THREAD|ObserverMgr.FIRE_IN_ASYNC)
public void dataChanged(Object dat){
JDLog.tag().i("dataChanged:"+dat.toString()+" trdid:"+Thread.currentThread().getName());
}
调用例子如下:
public void testPreference2() throws Exception {
File dataDir = getInstrumentation().getTargetContext().getFilesDir();
Preference p2 = Preference.obtain(dataDir, "test2");
ObserverMgr.register(this);
JDLog.tag().p("start ...");
ObjTest ot = new ObjTest();
ot.strtmp1 = "stage1";
ot.strtmp2 = "tmp1";
ot.tmp1=23;
ot.ltmp3 = 123L;
Thread.sleep(100);
}
对应的Preference类的实现如下:
package com.jd.mall.data;
import android.os.Bundle;
import android.os.Parcel;
import com.jd.mall.control.logsys.JDLog;
import com.litl.leveldb.DB;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
/**
* Created by luozhifan on 2015/01/12.
*
* process persistent bundle/object instance.
* auto fire update event into Observer("Preference.<key>") in default way;
* data save into leveldb with sync mode.
*/
public class Preference {
private Bundle b = null;
private Object obj = null;
private String pkgName = "";
private String observerKey;
private boolean enableNotify = true;
// private EventBus eb = new EventBus();
private ObserverEvent oe;
private static DB db = null ;
private static HashMap<string preference=""> globalPfc = new HashMap<string preference="">();
/*
@param key: define a persistent set
*/
private Preference(File datadir, String key) {
pkgName = key;
observerKey = "Preference."+pkgName;
oe = ObserverEvent.obtain(observerKey);
// eb.register(this);
if(!globalPfc.containsKey(key)) globalPfc.put(key, this);
if(db==null) {
db = new DB(new File(datadir, Constant.PERFERENCE_DB_PATH));
db.open();
}
}
/*
fetch singleton Preference instance
@param key: a persistent set's name
*/
static public Preference obtain(File datadir, String key) {
if(!globalPfc.containsKey(key)) {
new Preference(datadir, key);
}
return globalPfc.get(key);
}
/*
fetch saved data, return a Bundle type value.
can only use one of getBundle and get.
*/
public final synchronized Bundle getBundle() {
if (obj != null) return null;
if (b != null) return b;
b = new Bundle();
byte[] ret = db.get(pkgName.getBytes());
if(ret!=null) {
Parcel parcel = Parcel.obtain();
parcel.unmarshall(ret, 0, ret.length);
parcel.setDataPosition(0);
b.readFromParcel(parcel);
parcel.recycle();
}
return b;
}
/*
fetch saved val, return an any type value.
can only use one of getBundle and get.
*/
public final synchronized <t> T get() {
if (b != null) return null;
if(obj!=null) return (T)obj;
try {
ByteArrayInputStream b = new ByteArrayInputStream(db.get(pkgName.getBytes()));
ObjectInputStream o = new ObjectInputStream(b);
obj = o.readObject();
return (T)obj;
} catch (Exception e) {
}
return null;
}
public void notifyObserver(boolean enable){
enableNotify = enable;
}
public void update(Object val){
obj = val;
if(enableNotify) oe.post(val);
}
public void update(Bundle val){
b = (Bundle) val;
if(enableNotify) oe.post(val);
}
public synchronized void saveBundle(Bundle val) {
Parcel parcel = Parcel.obtain();
val.writeToParcel(parcel, 0);
db.put(pkgName.getBytes(), parcel.marshall());
parcel.recycle();
if(enableNotify) oe.post(val);
}
public synchronized void save(Object val) {
try {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(val);
db.put(pkgName.getBytes(), b.toByteArray());
if(enableNotify) oe.post(val);
}
catch(Exception e){
JDLog.trace(e);
}
}
}