近日,根据乐视网公告,腾讯子公司林芝利创、京东邦能、苏宁体育、TCL集团、深圳佰亿投资拟分别向新乐视智家注入3亿元,此外,世嘉控股、联想控股旗下的弘毅弘欣等也有参股。但乐视能否真正复兴,还需观察。
明天就是周六啦,提前祝大家周末愉快!
本篇来自
WuRichard
的投稿,分享了他自己的路由框架,希望对大家有所帮助。
WuRichard
的博客地址:
https://www.jianshu.com/u/fbeab77ee34b
KRouter
(
https://github.com/richardwrq/KRouter
)路由框架借助gradle插件、kapt(
https://blog.jetbrains.com/kotlin/2015/05/kapt-annotation-processing-for-kotlin
)实现了依赖注入、为Android平台页面启动提供路由功能。
源码不复杂,在关键地方也有注释说明,建议打算或正在使用kapt+kotlinpoet遇到坑的同学可以fork一下项目,或许能找到你想要的答案,只要将整个流程了解清楚了,相信你自己也能撸一个轮子出来,目前许多开源框架dagger、butter knife、greendao等实现原理都是一致的。
在组件化开发的实践过程中,当我完成一个模块的开发后(比如说这个模块中有一个Activity或者Service供调用者调用),其他模块的开发者要启动我这个模块中的Activity的代码我们再熟悉不过了:
val intent = Intent(this, MainActivity::class.java)
intent.putExtra("param1", "1")
intent.putExtra("param2", "2")
startActivity(intent)
当然,其他模块的开发人员需要知道我们这个Activity的类名以及传入的参数对应的key值(上面的param1和param2),这时候我就想,在每一个需要启动这个页面的地方都存在着类似的样板代码,而且被启动的Activity在取出参数对属性进行赋值时的代码也比较繁琐,于是在网上查找相关资料了解到目前主流的路由框架(ARouter、Router等)都支持这些功能,秉着尽量不重复造轮子的观念我fork了ARouter项目,但是阅读源码后发现其暂时不支持Service的启动,而我负责的项目里面全是运行在后台的Service。
紧接着也大概了解了一下其他一些框架,都存在一些不太满意的地方,考虑再三,干脆自己撸一个轮子出来好了。
首先来看一段最简单的发起路由请求的代码(Java调用):
KRouter.INSTANCE.create("krouter/main/activity?test=32")
.withFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.withString("test2", "this is test2")
.request();
其中krouter/main/activity?test=32为对应的路由路径,可以使用类似http请求的格式,在问号后紧接着的是请求参数,这些参数最终会自动包装在intent的extras中,也可以通过调用with开头的函数来配置请求参数。
上面的代码执行后最终会启动一个Activity,准确来说是一个带有@Route注解的Activity,它长这样:
@Route(path = "krouter/main/activity")
public class MainActivity extends Activity {
...
@Override
protected
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getIntent().getIntExtra("test", -1);
}
...
}
这是一个最基本的功能,怎么样,看起来还不错吧?跟大部分路由框架的调用方式差不多。现在主流的路由框架是怎么做到的呢?下面就看我一一道来。
在使用KRouter的API前首先需要为一些类添加注解:
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class Route(
val path: String,
val pathPrefix: String = "",
val pathPattern: String = "",
val name: String = "undefined",
val priority: Int = -1)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class Interceptor(
val priority: Int = -1,
val name: String = "DefaultInterceptor")
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.SOURCE)
annotation class Inject(
val name: String = "",
val isRequired: Boolean = false,
val desc: String = "No desc.")
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class Provider(
val value: String)
被注解的元素的信息最终被保存在对应的数据类中:
data class RouteMetadata(
val routeType: RouteType = RouteType.UNKNOWN,
val priority: Int = -1,
val name: String = "undefine",
val path: String = "",
val pathPrefix: String = "",
val pathPattern: String = "",
val clazz: Class = Any::class.java)
data class InterceptorMetaData(
val priority: Int = -1,
val name: String = "undefine",
val clazz: Class = Any::class.java)
data class InjectorMetaData(
val isRequired: Boolean = false,
val key: String = "",
val fieldName: String = "")
其中被
@Route
注解的类是Android中的四大组件和Fragment或者它们的子类(目前尚不支持Broadcast以及ContentProvider),被
@Route
注解的对象目前有3种处理方式:
-
若被注解的类是Activity的子类,那么最终的处理方式是startActivity;
-
若被注解的类是Service的子类,最终的处理方式有两种,也就 是Android中启动Service的两种方式,使用哪种启动方式取决于是否调用了withServiceConn函数添加了ServiceConnection;
-
若被注解的类是Fragment的子类,最终的处理方式是调用无参构造函数构造出这个类的实例,并调用setArguments(Bundle args)将请求参数传入Fragment的bundle中,最后返回该实例
被
@Interceptor
注解的类需实现IRouteInterceptor接口,这些类主要处理是否拦截路由的逻辑,比如某些需要登录才能启动的组件,就可以用到拦截器
@Inject
用于标记需要被注入的属性
被
@Provider
注解的类最终可以调用KRouter.getProvider(path: String)方法获取该类的对象,如果该类实现了IProvider接口,那么init(context: Context)方法将被调用
这些注解最终都不会被编译进class文件中,在编译时期这些注解会被收集起来最终交由不同的Annotation Processor去处理。
KRouter路由框架分为3个模块:
-
KRouter-api
模块,作为SDK提供API供应用调用,调用
KRouter-compiler
模块生成的类中的方法加载路由表,处理路由请求
-
KRouter-compiler
模块,各种注解对应的Processor的集合,编译期运行,负责收集路由组件,并生成kotlin代码
-
KRouter-gradle-plugin
模块,自定义gradle插件,在项目构建时期添加相关依赖以及相关参数的配置
KRouter-compiler
在介绍该模块之前如果有同学不知道Annotation Processor的话建议先阅读
Annotation Processing-Tool详解
https://blog.csdn.net/hj7jay/article/details/52180023
一小时搞明白注解处理器(Annotation Processor Tool)
https://blog.csdn.net/u013045971/article/details/53509237
这两篇文章,简单来说,APT就是javac提供的一个插件,它会搜集被指定注解所注解的元素(类、方法或者属性),最终将搜集到的这些交给注解处理器
Annotation Processor
进行处理,注解处理器通常会生成一些新的代码(推荐大名鼎鼎的square团队造的轮子javapoet(