1. 程式人生 > >自定義響應式程式設計框架兼備路由功能

自定義響應式程式設計框架兼備路由功能

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