自定義響應式程式設計框架兼備路由功能
阿新 • • 發佈:2019-01-07
從Rxjava中得到啟發,自己重寫了一套響應式框架,融合了阿里的ARoute部分功能,結構輕巧,擴充套件性強。
一、功能介紹
1、基於觀察者模式的響應式程式設計
2、頁面路由功能
3、依賴注入功能
二、核心類和介面解釋
-
此事件機制模組形象地描述為一家快遞公司,每一件快遞被打包成Event,我們事件機制模組主要做的事情有三件:
-
1、登記註冊物品供應商公司(就是EventRegister,一般為xxxFactory:生成receiver的工廠(供應商的客戶);
-
2、分配派送車倆運送快遞(分配派送的地方也就是xxxDispatcher),每一個供應商公司對應一輛派送車( 每一輛 具體的派送車也就是一個xxxScheduler),但分配派送的方式和派送車可以不同公司一起共享;
-
3、讓收貨人收到快遞(也就是EventReceiver)
-
-
主要成員類說明:
-
Event : 被打包成快遞的物件
-
EventHandler : 快遞公司的指揮部
-
EventFactory : 快遞公司
-
EventRegister : 供應商公司(具體例項不屬於Event模組),每一家供應商公司都要向快遞公司註冊登記,所以必須 實現此介面,供應商公司會告訴快遞公司貨物(Event)要發給哪個收件人。
-
EventReceiver : 收件人(具體例項不屬於Event模組),作為收件人必須實現此介面,在這裡可以收到快遞(Event)之後 根據實際需求處理快遞(Event)
-
三、響應式程式設計模組使用詳解
1、新增依賴和配置
引入方式:
dependencies { compile 'com.bfy:event-android:1.0.4' }
混淆配置:
無
2、直接使用
直接建立EventReceiver併發送:
/** * 使用這種方式不用EventFactory去繫結註冊器和分發器 */ private void handleTask() { EventBuilder.Event<Bundle, Object> event = new EventBuilder<Bundle, Object>() .register(new EventRegister() {//例項化一個註冊器來構建自己的Receiver接收器 @Override public EventReceiver getReceiver(String key) { //這裡我們不用接收器,所以返回null,如果使用者返回自己的接收器就不用下面的方法構建接收器了 return null; } }).receiver(new EventReceiver<Bundle, Object>() {//構建一個接收器, //如果用此方法構建了一個接收器,就可以不用註冊器去構建接收器了,所以上面可以返回null @Override public void onReceive(EventBuilder.Event<Bundle, Object> event) { Toast.makeText(MainActivity.this, "event android正在執行任務" , Toast.LENGTH_SHORT).show(); event.responseData = "響應資訊"; event.performCallback(event);//一定要呼叫這一句話,才能觸發後面的回撥 } }).dispatcher(new DefaultEventDispatcher()//構建分發器,使用預設的。非必要 ).interceptor(new Interceptor<Bundle, Object>() {//使用攔截器, 非必要 @Override public boolean intercept(EventState state, EventBuilder.Event<Bundle, Object> event) { return false;//返回true,任務會被攔截,中斷後續操作,這裡不使用攔截 } }).subscribeOn(/*Schedulers.cache()*/Schedulers.ui()//構建接收器中執行的任務所在的排程器, // 框架為我們設計了兩個排程器,一個是cache,一個是ui, 預設是cache執行緒,非必要 ).observeOn(Schedulers.ui()//構建回撥(觀察者)所在的排程器, 預設是cache執行緒,非必要 ).delay(0, null)//任務延時傳送, 非必要 .target(EventHandler.getInstance()//Event控制器,操作控制代碼。必要 ).callback(new EventCallback<Bundle, Object>() {//回撥, 非必要 @Override public void call(EventBuilder.Event<Bundle, Object> event) { mHandler.postDelayed(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "event android正在執行回撥" , Toast.LENGTH_SHORT).show(); } }, 2000); String response = event.responseData.toString();//可以從event中獲取響應資訊 event.release();//必要的時候可以在使用完event物件時釋放物件,避免記憶體洩露 } }).build(); event.send();//傳送 }
3、通過繫結註冊器和分發器來使用
我們需要在呼叫event傳送前註冊註冊器(實現了EventRigister介面的自定義類);
註冊器的主要目的是幫我們找到對應的接收器(實現了EventReceiver介面的自定義類);
一般註冊註冊器和接收器都是在Application或Activity的onCreate方法中;
EventRegister介面和EventReceiver介面的實現可以參考ContextReceiver類的實現。
//繫結業務模型,類ModelFactory是我自定義的註冊器,是實現了EventRegister介面的業務模型工廠類 ModelFactory.getInstance().registModelProxy(this, MainModel.class , Constant.MAIN_MODEL/*這是獲取接收器的key*/); //繫結分發器和註冊者業務類後,Event的registerType和receiverKey引數才能生效. //將業務模型工廠註冊到事件處理工廠中 EventFactory.getEventRegisterFactory().bindRegister( /*這個對應event中的registerType引數,event設定了registerType後就是通過這個查詢 到對應的註冊器,在這裡type引數可以自行定義,到時event填寫的時候對應就可以了*/ Constant.EVENT_TYPE_MODEL, ModelFactory.getRegister()/*把自己返回來*/); //下面這個註冊器是由框架內部提供的,主要功能是用來處理activity的啟動、傳送廣播和啟動服務。 EventFactory.getEventRegisterFactory().bindRegister( Constant.EVENT_TYPE_CONTEXT, ContextReceiver.getRegisterInstance()); //為業務工廠分配分發器,這一步是非必要的,可以選擇不繫結。 //給對應type的註冊器提供分發器;注意這裡的第一個引數type要與繫結的那個註冊器對應。 //如果不分配,則會使用預設的分發器,如果在呼叫時臨時配置了分發器則會使用臨時的分發器。 //分發器可以根據情況自行擴充套件,本框架提供了兩種預設的分發器。 EventFactory.getEventRegisterFactory().bindDispatcher(Constant.EVENT_TYPE_MODEL , new DefaultEventDispatcher()); EventFactory.getEventRegisterFactory().bindDispatcher(Constant.EVENT_TYPE_CONTEXT , new ContextEventDispatcher());
到這裡繫結工作做完了,上面這段程式碼建議寫在Application類中,通過這種方式實現Event機制可以將你自己專案的
業務模組和EventAndroid框架繫結;下面來講下怎麼呼叫:
Bundle bundle = new Bundle();//設定自己的請求引數 bundle.putString("keyword", key); bundle.putString("page", "1"); bundle.putString("pagesize", "30"); bundle.putString("userid", "-1"); bundle.putString("clientver", ""); bundle.putString("platform", "WebFilter"); bundle.putString("tag", "em"); bundle.putString("filter", "2"); bundle.putString("iscorrection", "1"); bundle.putString("privilege_filter", "0"); EventBuilder.Event<Bundle, JsonObject> event = new EventBuilder<Bundle, JsonObject>() .type(Constant.EVENT_TYPE_MODEL)//填寫好註冊器的型別 /*註冊器通過這個key找到對應的接收器,繼承了EventRegister介面的註冊器會實現getReceiver方法, 這個方法的引數只有一個,就是這裡傳過去的key。*/ .key(Constant.MAIN_MODEL) .requestId(0) .startTime(System.currentTimeMillis()) .target(EventHandler.getInstance()) .requestData(bundle) .callback(new EventCallback<Bundle, JsonObject>() { @Override public void call(EventBuilder.Event<Bundle, JsonObject> event) { parseData(event); } }).subscribeOn(Schedulers.cache()) .observeOn(Schedulers.ui()) .build(); event.send();
四、路由和依賴注入使用詳解
頁面路由模組依賴響應式程式設計模組,其他用法和阿里的ARouter使用方法基本一樣,不過閹割了一些功能。
1、新增依賴和配置
引入方式:
工程目錄中的build.gradle
buildscript { repositories { jcenter() maven{ url 'https://dl.bintray.com/haoxiangtt/maven' } } dependencies { //... classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //... } }
module中的build.gradle
//... apply plugin: 'com.neenbedankt.android-apt' android{ //... } //... dependencies { compile 'com.bfy:event-android:1.0.4' compile 'com.bfy:event-router:1.0.0' apt 'com.bfy:event-router-compiler:1.0.0' }
kotlin開發環境下的引入方式:
工程目錄中的build.gradle
buildscript { repositories { jcenter() maven{ url 'https://dl.bintray.com/haoxiangtt/maven' } } dependencies { //... //kotlin language plugin classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.10" classpath "org.jetbrains.kotlin:kotlin-android-extensions:1.2.10" //... } }
module中的build.gradle
//... apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' android{ //... } //... dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:1.2.10" compile 'com.bfy:event-android:1.0.4' compile 'com.bfy:event-router:1.0.0' kapt 'com.bfy:event-router-compiler:1.0.0' }
混淆配置:
-keep interface event.router.interfaces.**
-keep class event.router.annotation.**
-keep class event.router.RouterMapper{*;}
-keep class * implements event.router.interfaces.EventRelease{*;}
-keepclasseswithmembernames class event.router.Utils{*;}
-keepclasseswithmembernames class event.router.EventRouter{*;}
-keepclasseswithmembernames class event.router.PostCard{*;}
-keep class * implements event.router.interfaces.EventRelease{*;}
#-keep class event.** ##如果上述混淆報錯, 直接keep所有
-keepclasseswithmembernames @event.router.annotation.* class *{
<init>();
}
-keepclasseswithmembernames class * {
@event.router.annotation.* <methods>;
}
-keepclasseswithmembernames class * {
@event.router.annotation.* <fields>;
}
2、添加註解
新增頁面路由註解
@Router(path = "/test/hello", type = Router.Type.COMPONENT_ACTIVITY) public class HelloActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_hello); } }
新增業務模型路由註解
@Router(path = "/test/model1", type = Router.Type.COMPONENT_MODEL) public class Model1 { public void show(Context context, String msg) { Toast.makeText(context, msg + "->我的hashCode=" + hashCode(), Toast.LENGTH_SHORT).show(); } }
3、初始化路由SDK
在application或者Activity的Oncreate方法裡都可以。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //... //初始化路EventRouterSDK EventRouter.getInstant().init(this); //... }
4、發起路由
/** * 頁面跳轉新介面 */ private void route() { EventRouter.getInstant().build("/test/hello"). withRequestCode(5002) .withFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) .withContext(this) .letsGo(); }
5、新增依賴注入解耦業務需求
@Router(path = "/test/main", type = Router.Type.COMPONENT_ACTIVITY) public class MainActivity extends AppCompatActivity implements View.OnClickListener{ //path表示需要注入物件的路由路徑,singleton表示是否使用單例模式 //如果不配置path,表示使用屬性對應的型別進行注入 @Autowired(path = "/test/model1", singleton = true) Model1 model1;//需要注入的業務模型 Model1 model11;//需要注入的業務模型 @Autowired Model2 model2;//需要注入的業務模型 Model2 model22;//需要注入的業務模型 //使用設定器注入 @Autowired(singleton = true) //singleton表示是否使用單例 //如果不配置path,表示使用傳入引數對應的型別進行注入 protected void setModel1(Model1 model) { model11 = model; } //使用設定器注入 @Autowired(path = "/test/model2") public void setModel2(Model2 model) { model22 = model; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //... //初始化路由SDK EventRouter.getInstant().init(this); //新增依賴注入 eventRelease = EventRouter.getInstant().inject(this); //... } }
五、其他
1、日誌開關配置
EventConfig.setDebugMode(true);