ARouter除了路由寻址跳转之外,还可以通过注解的方式传递参数,类似于Intent的作用
1 Paramter注解1.1 TypeElement 和 Element1.2 Element常用的API2 APT生成参数接收代码2.1 TypeMirror 元素类型2.2 TypeMirror怎么判断一个类是否继承自Activity3 ParamterManager4 RouterManager
1 Paramter注解@Target(AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.PROPERTY, AnnotationTarget.FILE) @Retention(AnnotationRetention.BINARY) annotation class Parameter( val name:String = "" )
像LayRouter一样,声明一个注解,创建一个注解处理类,在service中注册
@AutoService(Processor::class) class ParameterProcessor : AbstractProcessor() { private lateinit var message:Messager private lateinit var filer: Filer private lateinit var elementUtils: Elements private lateinit var typeUtils:Types //仓库 //key TypeElement Activity 相当于父节点 //value 参数数组 一个Activity中使用Parameter注解的参数 private val paramMap = mutableMapOf>() override fun getSupportedAnnotationTypes(): MutableSet { return mutableSetOf(Parameter::class.java.canonicalName) } override fun getSupportedSourceVersion(): SourceVersion { return SourceVersion.RELEASE_8 } override fun init(processingEnv: ProcessingEnvironment?) { super.init(processingEnv) //打印日志 message = processingEnv!!.messager //输出kotlin文件 filer = processingEnv.filer elementUtils = processingEnv.elementUtils typeUtils = processingEnv.typeUtils } override fun process(p0: MutableSet ?, p1: RoundEnvironment?): Boolean { if(p0.isNullOrEmpty()){ return false } message.printMessage(Diagnostic.Kind.NOTE,"process ------->") //获取全部注解过Parameter的参数 val set = p1!!.getElementsAnnotatedWith(Parameter::class.java) set.forEach { element -> //加入集合 //判断当前属性的父节点 val typeElement:TypeElement = element.enclosingElement as TypeElement if(paramMap.containsKey(typeElement)){ val list = paramMap[typeElement] list!!.add(element) }else{ //如果不存在,就需要重新创建集合 val list = mutableListOf () list.add(element) paramMap[typeElement] = list } } //需要处理 message.printMessage(Diagnostic.Kind.NOTE,"----------> $paramMap") return false } }
使用方式跟LayRouter注解时一致,需要提到一个新的知识点
1.1 TypeElement 和 ElementTypeElement是Element的一个子类,通常来说,Element就是一个节点元素,像TypeElement就是代表一个类或者接口,例如MainActivity…PackageElement代表包元素,VariableElement代表参数元素(字段、枚举、形参等),ExecutableElement代表方法元素(某个类 接口的函数)
总体来看,所有的节点都可以看做是Element
1.2 Element常用的APIpublic interface Element extends AnnotatedConstruct { TypeMirror asType(); //返回Element的类型 ElementKind getKind(); SetgetModifiers(); Name getSimpleName(); //返回当前元素的父元素 Element getEnclosingElement(); //返回当前元素的全部子元素 List extends Element> getEnclosedElements(); }
Element的类型包括如下几种:
public enum ElementKind { PACKAGE, ENUM, CLASS, ANNOTATION_TYPE, INTERFACE, ENUM_CONSTANT, FIELD, PARAMETER, LOCAL_VARIABLE, EXCEPTION_PARAMETER, METHOD, CONSTRUCTOR, STATIC_INIT, INSTANCE_INIT, TYPE_PARAMETER, OTHER, RESOURCE_VARIABLE, MODULE; private ElementKind() { } //判断是不是类 public boolean isClass() { return this == CLASS || this == ENUM; } //是不是接口 public boolean isInterface() { return this == INTERFACE || this == ANNOTATION_TYPE; } //是不是属性 public boolean isField() { return this == FIELD || this == ENUM_CONSTANT; } }2 APT生成参数接收代码
class MainActivityParams : ParameterGet { override fun getParameter(activity: Any) { val activityInstance = activity as MainActivity activityInstance.age = activityInstance.intent.getStringExtra("age").toString() activityInstance.name = activityInstance.intent.getStringExtra("name").toString() activityInstance.subject = activityInstance.intent.getStringExtra("subject").toString() } }
生成上述模板代码,其中getParameter的参数activity,就是携带参数跳转到的目标Activity,那么在路由跳转的时候,通过在Intent中传入参数,在目标Activity中接收
override fun process(p0: MutableSet?, p1: RoundEnvironment?): Boolean { if (p0.isNullOrEmpty()) { return false } message.printMessage(Diagnostic.Kind.NOTE, "process ------->") //获取全部注解过Parameter的参数 val set: Set = p1!!.getElementsAnnotatedWith(Parameter::class.java) set.forEach { element -> //加入集合 //判断当前属性的父节点 val typeElement = element.enclosingElement if (paramMap.containsKey(typeElement)) { val list = paramMap[typeElement] list!!.add(element) } else { //如果不存在,就需要重新创建集合 val list = mutableListOf () list.add(element) paramMap[typeElement] = list } } //需要处理 message.printMessage(Diagnostic.Kind.NOTE, "----------> $paramMap") if (paramMap.isEmpty()) { return false } createParamFile() return false } private fun createParamFile() { paramMap.forEach { (typeElement, mutableList) -> //创建方法 val func = FunSpec.builder("getParameter") .addModifiers(KModifier.OVERRIDE) .addParameter("activity", Any::class) .addStatement( "val %N = activity as %T", property, typeElement.asType().asTypeName() ) mutableList.forEach { element -> //Parameter注解的赋值 val name = element.getAnnotation(Parameter::class.java).name func.addStatement( "%N.%L = %N.intent.getStringExtra(%S).toString()", property, element.simpleName.toString(), property, element.simpleName.toString() ) } val classBuilder = TypeSpec.classBuilder(typeElement.simpleName.toString() + "Params") .addSuperinterface(ClassName(ipackage, iname)) .addFunction(func.build()) .build() val fileSpec = FileSpec.builder("", typeElement.simpleName.toString() + "Params") .addType(classBuilder).build() fileSpec.writeTo(filer) } } }
老规矩,只说新的知识点,但是好像并没有~~
最终生成的模板代码
public class RegisterActivityParams : ParameterGet { public override fun getParameter(activity: Any): Unit { val activityInstance = activity as RegisterActivity //在这里就赋值了 activityInstance.sex = activityInstance.intent.getStringExtra("sex").toString() } }
那么在路由跳转的时候,通过Intent携带sex参数,跳转到RegisterActivity
This is last chapter code,please find this in last chapter
val r = ARouteGroupregister() val registerRouter = r.getARouteGroup()["register"] val registerActivityClass = registerRouter!!.getARoutePath()["register/RegisterActivity"] startActivity(Intent(this,registerActivityClass!!.getModel().java).putExtra("sex","男性"))
在RegisterActivity中调用getParameter,其实已经对sex:String赋值
@LayRouter(group = "register",path = "register/RegisterActivity") class RegisterActivity : AppCompatActivity() { @Parameter lateinit var sex:String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_register) RegisterActivityParams().getParameter(this) findViewById(R.id.tv_info).text = sex } }
这是特殊的一种情况,所有的属性都是字符串,如果有其他类型的字符串,就不能只用 intent.getStringExtra输出代码,就会报错,因此需要判断属性的类型
2.1 TypeMirror 元素类型TypeMirror是用来判断Element的类型,是基本数据类型,还是类,还是方法…
mutableList.forEach { element -> //Parameter注解的赋值 val name = element.getAnnotation(Parameter::class.java).name val typeMirror = element.asType() var str = "intent.getStringExtra(%S).toString()" if(typeMirror.kind == TypeKind.INT){ str = "intent.getIntExtra(%S,0)" }else if(typeMirror.kind == TypeKind.BOOLEAN){ str = "intent.getBooleanExtra(%S,false)" } func.addStatement( "%N.%L = %N.$str", property, element.simpleName.toString(), property, element.simpleName.toString() ) }
因为是调用Element的asType方法,肯定是判断当前Element是哪些子类,因此通过判断Element的类型,来执行不同的语句
public class RegisterActivityParams : ParameterGet { public override fun getParameter(activity: Any): Unit { val activityInstance = activity as RegisterActivity activityInstance.sex = activityInstance.intent.getStringExtra("sex").toString() activityInstance.age = activityInstance.intent.getIntExtra("age",0) activityInstance.isOk = activityInstance.intent.getBooleanExtra("isOk",false) } }2.2 TypeMirror怎么判断一个类是否继承自Activity
见上一节的代码
val activityMirror = elementTool!!.getTypeElement(ACTIVITY_PACKAGE).asType() if(typeTool!!.isSubtype(element.asType(),activityMirror)){ routeBean.setType(RouterType.ACTIVITY) }else{ //抛出异常 throw Exception("@LayRouter注解只能在Activity或者Fragment上使用") }
每个Element都有自己的TypeMirror,通过TypesUtils,就可以判断,一个元素是否是继承自某个类,通过TypesUtils 的 isSubtype 方法
3 ParamterManager在目标Activity中,每次需要创建一个对应的ParameterGet对象,因为实现类本身就是根据Activity创建的,因此可以通过一个管理类,来自动查找实现类
class ParameterManager { companion object{ val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ParameterManager() } } //定义缓存 private val map:MutableMap= mutableMapOf() fun loadParams(activity:Any) : ParameterGet?{ //获取绑定的activity的名称 val name = activity::class.simpleName!! if(map.containsKey(name)){ return map[name] } //如果没有存在map集合中 val className = Class.forName(name + "Params") map[name] = className.newInstance() as ParameterGet return map[name] } }
在任何Activity中,通过这一行代码,就能够实现参数的传递
ParameterManager.instance.loadParams(this)!!.getParameter(this)4 RouterManager
再回到我们最初的愿景:一行代码,搞定路由通信传参
val targetGroup = ARouter_Group_register() val registerRouter = targetGroup.getARouteGroup()["register"] val registerActivityClass = registerRouter!!.getARoutePath()["register/RegisterActivity"] val intent = Intent().apply { setClass(this@MainActivity,registerActivityClass!!.getModel().java) putExtra("sex","男性") putExtra("age",25) putExtra("isOk",true) } startActivity(intent)
最开始,Activity的跳转,首先找到目标Activity的Group,然后再找到目标Activity的Path组合,查找要跳转的路由路径
class RouterManager { companion object{ val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { RouterManager() } } //需要两个缓存,组的缓存,路径的缓存 private val mGroupMap:MutableMap= mutableMapOf() private val mPathGroup:MutableMap = mutableMapOf() private var group:String = "" private var path:String = "" fun build(path:String) : RouterManager?{ if(path.isEmpty()){ return null } //获取group val splitArray = path.split("/") group = splitArray[0] this.path = path return this } fun navigation(context: Context){ //查找组 ARouter_Group_register val targetGroup = "ARouter_Group_$group" val targetGroupImpl: IARoutGroup //从group中查找 if(mGroupMap.containsKey(group)){ targetGroupImpl = mGroupMap[group]!! }else{ val groupClass = Class.forName(targetGroup) targetGroupImpl = groupClass.newInstance() as IARoutGroup mGroupMap[group] = targetGroupImpl } val routeBean: RouteBean //查找路由 if(mPathGroup.containsKey(path)){ routeBean = mPathGroup[path] as RouteBean }else{ val targetRouterPath = targetGroupImpl.getARouteGroup()[group]!! routeBean = targetRouterPath.getARoutePath()[path] as RouteBean mPathGroup[group] = routeBean } val intent = Intent().apply { setClass(context,routeBean.getModel().java) } context.startActivity(intent) } }
最终通过一行代码,实现路由跳转
RouterManager.instance.build("app/SecondActivity")!!.navigation(this)
如果想要实现带参数传递,实现如下,先写一个BundleManager用来传递参数
class BundleManager private constructor(){ companion object { val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { BundleManager() } } private val bundle = Bundle() fun withString(key:String,value:String) : BundleManager{ bundle.putString(key,value) return this } fun withInt(key: String,value: Int) : BundleManager{ bundle.putInt(key,value) return this } fun withBoolean(key: String,value: Boolean) : BundleManager{ bundle.putBoolean(key,value) return this } fun getBundle():Bundle{ return bundle } fun navigation(context: Context) : RouterManager?{ if(!bundle.isEmpty){ //在这里直接路由跳转 return RouterManager.instance.navigation(context,this) } return null } }
修改后的RouteManager如下
class RouterManager private constructor(){ companion object{ val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { RouterManager() } } //需要两个缓存,组的缓存,路径的缓存 private val mGroupMap:MutableMap= mutableMapOf() private val mPathGroup:MutableMap = mutableMapOf() private var group:String = "" private var path:String = "" fun build(path:String) : BundleManager?{ if(path.isEmpty()){ return null } //获取group val splitArray = path.split("/") group = splitArray[0] this.path = path return BundleManager.instance } fun navigation(context: Context,manager: BundleManager) : RouterManager{ //查找组 ARouter_Group_register val targetGroup = "ARouter_Group_$group" val targetGroupImpl: IARoutGroup //从group中查找 if(mGroupMap.containsKey(group)){ targetGroupImpl = mGroupMap[group]!! }else{ val groupClass = Class.forName(targetGroup) targetGroupImpl = groupClass.newInstance() as IARoutGroup mGroupMap[group] = targetGroupImpl } val routeBean: RouteBean //查找路由 if(mPathGroup.containsKey(path)){ routeBean = mPathGroup[path] as RouteBean }else{ val targetRouterPath = targetGroupImpl.getARouteGroup()[group]!! routeBean = targetRouterPath.getARoutePath()[path] as RouteBean mPathGroup[group] = routeBean } val intent = Intent().apply { setClass(context,routeBean.getModel().java) putExtras(manager.getBundle()) } context.startActivity(intent,manager.getBundle()) return this } }
最后,我们实现了一开始的愿景,通过一行代码就实现了路由的跳转(携带参数)
RouterManager.instance.build("register/RegisterActivity")!! .withString("sex","男") .withInt("age",31) .withBoolean("isOk",true) .navigation(this)
End~~~~~
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)