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