项目源码地址:Qiaoba框架github地址
compile 'com.xiaoxiao.qiaoba:qiaoba:1.0.3' //主要实现业务逻辑的模块
compile 'com.xiaoxiao.qiaoba:protocol-interpreter:1.0.3'//apt编译期处理代码
compile 'com.xiaoxiao.qiaoba:protocol-annotation:1.0.3'//apt使用的注解
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
在需要使用的module目录下增加:
apply plugin: 'com.neenbedankt.android-apt'
-keep class com.xiaoxiao.qiaoba.**{*;}
-keep @com.xiaoxiao.qiaoba.annotation.communication.Provider class *{
;
}
-keep @com.xiaoxiao.qiaoba.annotation.communication.Caller class *{
;
}
-keep @com.xiaoxiao.qiaoba.annotation.communication.CallBack class *{
;
}
-keep @com.xiaoxiao.qiaoba.annotation.communication.CallbackParam class *{
;
}
-keep class com.xiaoxiao.qiaoba.**{*;}
-keep @com.xiaoxiao.qiaoba.annotation.communication.Provider class *{
@com.xiaoxiao.qiaoba.annotation.communication.CommuApiMethod ;
}
-keep @com.xiaoxiao.qiaoba.annotation.communication.Caller class *{
@com.xiaoxiao.qiaoba.annotation.communication.CommuApiMethod ;
}
-keep @com.xiaoxiao.qiaoba.annotation.communication.CallBack class *{
;
}
-keep @com.xiaoxiao.qiaoba.annotation.communication.CallbackParam class *{
;
}
4.具体的使用:RouterInterpreter.init(getApplicationContext());
功能1:通过路由启动Activity第一种方式:需要对Activity配置对应的路由信息,比如路由信息如下:xl://main:8888/demo(启动xl:对应scheme, main:host(可以对应你当前的组件的业务功能),8888:端口号,/demo:path(对应具体Activity))对应Activity的配置如下:
通过这个链接,可以在在html中直接打开,例如xl://main:8888/demo">在另外的组件中启动这个页面,首先需要创建一个接口如下:
public interface IRouterUri { @RouterUri("xl://main:8888/demo")//此注解对应的是 url的地址 public void jumpToDemo(@RouterParam("key") String key);//RouterParam 对应的参数,里面值是参数名 //如果增加页面,可以在这里增加对应的方法即可 }
启动页面的代码如下:
RouterInterpreter.getInstance().create(IRouterUri.class).jumpToDemo("second module data");
这样的好处:面向接口编程,不关心内部实现,满足依赖倒置原则,使用者只需要知道要启动的uri,设置对应的注解就好了。
还可以直接通过uri地址字符串来启动:
RouterInterpreter.getInstance().openRouterUri("xl://main:8888/linkdemo?key=fuck&ddd=you");
获取uri中参数的方式如下:
Uri data = getIntent().getData(); final String key = data.getQueryParameter("key");
使用Builder的方式:
支持设置参数;RouterInterpreter.getInstance() .build("xl://main:8888/linkdemo") .withString("key","fuck") .withString("ddd","you") // .addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) .requestCode(12, SecondDemoActivity.this) .callback(new RouterCallback() { @Override public void onSuccess() { Toast.makeText(SecondDemoActivity.this, "Router to other page success.", Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable error) { } }) .navigation();
支持设置requestCode,相当于使用startActviityForResult()的方式启动页面
支持设置启动Activity的Flag(默认是FLAG_ACTIVITY_NEW_TASK)
支持设置接口回调,支持成功和失败的回调
第二种方式:不想在Acitivity中配置相关的uri的信息,就想通过指定的uri启动对应的页面。
需要在对应的Activity上添加对应注解,如下:
@RouterLinkUri("xl://main:8888/linkdemo") public class RouterLinkDemoActivity extends AppCompatActivity {
启动的方式如上,但是这种方式,因为没有为Activity配置对应的信息,所以通过上面的getIntent().getData()是获取不到,但是我默认的处理是,通过bundle传递,key就是uri中的key,value就是uri中对应的值。获取方式如下:
Intent intent = getIntent(); String val1 = intent.getStringExtra("key"); String val2 = intent.getStringExtra("ddd");
功能2:跨组件通信
比如上面的secondmodule模块想要调用主module app 中下面的业务方法:
这个时候需要使用两个注解Provider(提供者) 和 Caller(调用者),对于上面提供业务功能的类需要打上注解Provider。在secondmodule中调用的接口打上注解Caller。示例如下:public class TestService { public void doService(Context context, String str){ Toast.makeText(context,"come from main module : "+ str, Toast.LENGTH_SHORT).show(); } }
注意:上面的Provider 和 Caller中的值必须相同,因为这是他们之间建立桥梁的关键;并且这个值是不能重复的。还是就是调用方的调用对应的提供放的业务方法的方法名和参数要相同。@Provider("test") public class TestService { public void doService(Context context, String str){ Toast.makeText(context,"come from main module : "+ str, Toast.LENGTH_SHORT).show(); } } @Caller("test") public interface TestService { public void doService(Context context, String str); }
支持Provider对Caller 1对多支持;
Provider注解的value是String数组,可以每一个Caller对应一个单独的value值和Provider对应;
也可以Provider的value就一个值,所有的Caller的value值都相同(注意:这里所指相同是一个api方法所对应的Provider的值)
调用的业务功能的实现如下:
上面实现的好处:面向接口编程,组件间完全解耦,符合依赖倒置原则。业务功能提供方,只需要提供对应的接口就好,具体联系通过apt动态生成代码,然后具体实现通过动态代理在运行时去执行。ProtocolInterpreter.getInstance().create(TestService.class).doService(SecondDemoActivity.this, "second activity show toast");
api接口回调参数的支持:1.需要使用CallBack 和 CallbackParam两个注解2.还是上面的示例,增加回调参数,提供方回调参数对应的回调接口@CallBack("test") public interface TestCallback { void showHello(String msg); int getNum(); }
调用方使用CallbackParam注解:@Provider({"test", "test2"}) public class TestService { public void doService(Context context, String str, TestCallback callback){ Toast.makeText(context,"come from main module : "+ str + ";;; num from other mudule : " + callback.getNum(), Toast.LENGTH_SHORT).show(); callback.showHello("hello"); } }
定义回调接口原型@CallbackParam("test") public interface TestCallback { void showHello(String msg); int getNum(); }
对应Caller的api接口原型
调用方调用提供方api接口:@Caller("test") public interface Test2Service { void doService(Context context, String str, TestCallback callback); }
ProtocolInterpreter.getInstance().create(Test2Service.class).doService(SecondDemoActivity.this, "second activity show toast", new TestCallback(){ @Override public void showHello(final String msg) { new Handler().postDelayed(new Runnable() { @Override public void run() { Toast.makeText(SecondDemoActivity.this, "say hello : " + msg + " in second activity", Toast.LENGTH_SHORT).show(); } }, 3000); } @Override public int getNum() { return 99; } });
五、总结
目前,将基本功能都实现了,后面会对本框架的原理和源码进行剖析。代码已经开源到github上,欢迎star和fork,感激不尽。如果大家有更好的设计方式,或者更好的实现方式和扩展,欢迎指导,感激不尽。