自定义的响应式编程框架(路由框架)-EventAndroid

最近研究了一下Rxjava源码,因为公司的需求不能导入过多的第三方库,所以只能自己实现一个响应式编程的框架来实现线程的调度, 于是从Rxjava中得到启发,精简出了自己需要的功能重写了一份属于自己的框架,并且融合了阿里的Aroute部分功能,我给它取名叫EventAndroid,希望大家喜欢,有什么问题可以及时跟我提出,或者有什么好的建议希望大家分享给我_。下面贴一下自实现框架的 readme简介:

一、功能介绍

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

源码地址:https://github.com/haoxiangtt/EventAndroid
CSDN文章链接:http://blog.csdn.net/haoxiangtt/article/details/77946315
安卓巴士相关链接:http://www.apkbus.com/thread-281922-1-1.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335