博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android组件化专题-路由动态注入跳转参数以及获取其他模块的fragment
阅读量:7107 次
发布时间:2019-06-28

本文共 15920 字,大约阅读时间需要 53 分钟。

,我们对路由框架基本实现了,Activity之间当跳转和模块间当通信。

现在思考一个问题: 不管是在Activity或者Fragment,跳转都会传递一些参数,然后在对应对Activity或着Fragment获取对应对参数,都要写大量重复的代码,然而我们作为一名有素质有梦想的码农,我们是不可以做这种搬砖的操作的,不想当大牛当码农不是好码农。

那么我们如何用优雅的代码,解决这个问题呢?请看下面分解

路由动态注入跳转参数

原生的获取intent跳转传递过来的参数:

Intent intent = getIntent();final String path = intent.getStringExtra("path");......复制代码

同时还有fragment的参数传递等。

如果稍微进行一些封装的话可以这样写:

public class MainActivityExtra {    public static void loadExtra(Main2Activity main2Activity) {        Intent intent = main2Activity.getIntent();        main2Activity.path = intent.getStringExtra("path");                ......    }}复制代码

上述不管哪种写法,都是相当麻烦和大量的重复代码。

最为一名有梦想的码农,我理想中的写法:

在相应的Activity,通过一个注解就可以拿到跳转传递过来的参数的值,然后直接使用。

@Extrapublic String path;复制代码

那么我们如何实现呢? 其实很简单,我们通过注解拿到父类Activity,然后注解变量的类型和名称,然后我们动态生成一个类,通过原生的方式来实现参数获取。

其实跟上几篇的文章是一样的原理,这里就不再多复述了这是链接

下面就直接一堆代码,抛给你

  1. 首先声明注解
@Target(ElementType.FIELD)@Retention(RetentionPolicy.CLASS)public @interface Extra {    String name() default "";}复制代码
  1. 注解处理器处理注解,这里面的逻辑其实非常简单,主要是看你对APT使用是不是熟练
@AutoService(Processor.class)@SupportedSourceVersion(SourceVersion.RELEASE_7)@SupportedAnnotationTypes({Consts.EXTRA_NAME})@SupportedOptions({Consts.ARGUMENTS_NAME})public class ExtraProcessor extends AbstractProcessor {    /**     * key:类节点 value:需要注入的属性节点集合     */    private Map
> extraMap = new HashMap<>(); private Elements elementUtils; private Types typeUtils; private Filer filer; private Log log; private Messager messager; @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); elementUtils = processingEnvironment.getElementUtils(); typeUtils = processingEnvironment.getTypeUtils(); filer = processingEnvironment.getFiler(); messager = processingEnvironment.getMessager(); log = Log.newLog(messager); } @Override public boolean process(Set
set, RoundEnvironment roundEnvironment) { if (null != set && !set.isEmpty()) {//注意这里必须要判断set.isEmpty() 否则会走两遍 log.i("process"); //拿到注有Extra 的节点集合 Set
elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(Extra.class); if (null != elementsAnnotatedWith) { try { saveExtras(elementsAnnotatedWith); generateExtras(); } catch (Exception e) { e.printStackTrace(); } } return true; } return false; } /** * 保存节点的信息 * * @param elementsAnnotatedWith */ private void saveExtras(Set
elementsAnnotatedWith) { for (Element element : elementsAnnotatedWith) { //获取注解父类的节点类型 TypeElement enclosingElement = (TypeElement) element.getEnclosingElement(); if (extraMap.containsKey(enclosingElement)) { extraMap.get(enclosingElement).add(element); } else { List
list = new ArrayList<>(); list.add(element); extraMap.put(enclosingElement, list); } } } private MethodSpec.Builder builder; private TypeMirror parcelableType; private TypeMirror iServiceType; private TypeElement extraElement; private TypeMirror activity; /** * 生成表 */ private void generateExtras() { //支持Activity和Fragment activity = elementUtils.getTypeElement(Consts.Activity).asType(); extraElement = elementUtils.getTypeElement(Consts.Extra); parcelableType = elementUtils.getTypeElement(Consts.PARCELABLE).asType(); iServiceType = elementUtils.getTypeElement(Consts.Service).asType(); log.i("generateExtras"); //参数 ParameterSpec target = ParameterSpec.builder(TypeName.OBJECT, "target").build(); if (!Utils.isEmpty(extraMap)) { //遍历被Extra注解属性的类 for (Map.Entry
> entry : extraMap.entrySet()) { TypeElement classType = entry.getKey(); log.i("isSubtype:" + typeUtils.isSubtype(classType.asType(), activity) + " | " + classType.asType()); if (typeUtils.isSubtype(classType.asType(), activity)) { generateClass(target, entry, classType); } else { throw new RuntimeException("[Just Support Activity Field] : " + classType + " --> " + typeUtils.isSubtype(classType.asType(), activity)); } } } } public void generateClass(ParameterSpec target, Map.Entry
> entry, TypeElement classType) { builder = MethodSpec.methodBuilder(Consts.EXTRA_METHOD_NAME)//方法名 .addAnnotation(Override.class)//注解 .addModifiers(Modifier.PUBLIC)//作用域 .addParameter(target);//添加参数 log.i("generate method"); //设置函数体 addFuncationBody(entry, classType); log.i("generate type"); //生成Java类 TypeSpec typeSpec = TypeSpec.classBuilder(classType.getSimpleName() + "$$Extra") .addSuperinterface(ClassName.get(extraElement)) .addModifiers(Modifier.PUBLIC) .addMethod(builder.build()) .build(); try { //生成Java类文件 log.i("package name:" + ClassName.get(classType).packageName()); JavaFile.builder(ClassName.get(classType).packageName(), typeSpec).build().writeTo(filer); } catch (IOException e) { e.printStackTrace(); log.i("package name error"); } } private void addFuncationBody(Map.Entry
> entry, TypeElement classType) { for (Element element : entry.getValue()) { //$T t = ($T)target builder.addStatement("$T t = ($T)target", classType, classType); //遍历注解节点 生成函数体 TypeMirror typeMirror = element.asType();//获取注解节点的类型 //获取TypeKind 枚举类型的序列号 int type = typeMirror.getKind().ordinal(); //获取属性名 String fieldName = element.getSimpleName().toString(); //获取注解的值 String extraName = element.getAnnotation(Extra.class).name(); //判断直接的值为空的情况下的处理 extraName = Utils.isEmpty(extraName) ? fieldName : extraName; String defaultValue = "t." + fieldName; String statement = defaultValue + " = t.getIntent()."; if (type == TypeKind.BOOLEAN.ordinal()) { statement += "getBooleanExtra($S, " + defaultValue + ")"; } else if (type == TypeKind.BYTE.ordinal()) { statement += "getByteExtra($S, " + defaultValue + ")"; } else if (type == TypeKind.SHORT.ordinal()) { statement += "getShortExtra($S, " + defaultValue + ")"; } else if (type == TypeKind.INT.ordinal()) { statement += "getIntExtra($S, " + defaultValue + ")"; } else if (type == TypeKind.LONG.ordinal()) { statement += "getLongExtra($S, " + defaultValue + ")"; } else if (type == TypeKind.CHAR.ordinal()) { statement += "getCharExtra($S, " + defaultValue + ")"; } else if (type == TypeKind.FLOAT.ordinal()) { statement += "getFloatExtra($S, " + defaultValue + ")"; } else if (type == TypeKind.DOUBLE.ordinal()) { statement += "getDoubleExtra($S, " + defaultValue + ")"; } else { //数组类型 if (type == TypeKind.ARRAY.ordinal()) { addArrayStatement(statement, fieldName, extraName, typeMirror, element); } else { //Object addObjectStatement(statement, fieldName, extraName, typeMirror, element); } return; } log.i("generate statement:" + statement); builder.addStatement(statement, extraName); } } /** * 添加对象 String/List/Parcelable * * @param statement * @param extraName * @param typeMirror * @param element */ private void addObjectStatement(String statement, String fieldName, String extraName, TypeMirror typeMirror, Element element) { //Parcelable if (typeUtils.isSubtype(typeMirror, parcelableType)) { statement += "getParcelableExtra($S)"; } else if (typeMirror.toString().equals(Consts.STRING)) { statement += "getStringExtra($S)"; } else if (typeUtils.isSubtype(typeMirror, iServiceType)) {// TestService testService = (TestService) DNRouter.getInstance().build("/main/service1")// .navigation();// testService.test(); statement = "t." + fieldName + " = ($T) $T.getInstance().build($S).navigation()"; builder.addStatement(statement, TypeName.get(element.asType()), Consts.ROUTER, extraName); return; } else { //List TypeName typeName = ClassName.get(typeMirror); //泛型 if (typeName instanceof ParameterizedTypeName) { //list 或 arraylist ClassName rawType = ((ParameterizedTypeName) typeName).rawType; //泛型类型 List
typeArguments = ((ParameterizedTypeName) typeName) .typeArguments; if (!rawType.toString().equals(Consts.ARRAYLIST) && !rawType.toString() .equals(Consts.LIST)) { throw new RuntimeException("Not Support Inject Type:" + typeMirror + " " + element); } if (typeArguments.isEmpty() || typeArguments.size() != 1) { throw new RuntimeException("List Must Specify Generic Type:" + typeArguments); } TypeName typeArgumentName = typeArguments.get(0); TypeElement typeElement = elementUtils.getTypeElement(typeArgumentName .toString()); // Parcelable 类型 if (typeUtils.isSubtype(typeElement.asType(), parcelableType)) { statement += "getParcelableArrayListExtra($S)"; } else if (typeElement.asType().toString().equals(Consts.STRING)) { statement += "getStringArrayListExtra($S)"; } else if (typeElement.asType().toString().equals(Consts.INTEGER)) { statement += "getIntegerArrayListExtra($S)"; } else { throw new RuntimeException("Not Support Generic Type : " + typeMirror + " " + element); } } else { throw new RuntimeException("Not Support Extra Type : " + typeMirror + " " + element); } } builder.addStatement(statement, extraName); } /** * 添加数组 * * @param statement * @param fieldName * @param typeMirror * @param element */ private void addArrayStatement(String statement, String fieldName, String extraName, TypeMirror typeMirror, Element element) { //数组 switch (typeMirror.toString()) { case Consts.BOOLEANARRAY: statement += "getBooleanArrayExtra($S)"; break; case Consts.INTARRAY: statement += "getIntArrayExtra($S)"; break; case Consts.SHORTARRAY: statement += "getShortArrayExtra($S)"; break; case Consts.FLOATARRAY: statement += "getFloatArrayExtra($S)"; break; case Consts.DOUBLEARRAY: statement += "getDoubleArrayExtra($S)"; break; case Consts.BYTEARRAY: statement += "getByteArrayExtra($S)"; break; case Consts.CHARARRAY: statement += "getCharArrayExtra($S)"; break; case Consts.LONGARRAY: statement += "getLongArrayExtra($S)"; break; case Consts.STRINGARRAY: statement += "getStringArrayExtra($S)"; break; default: //Parcelable 数组 String defaultValue = "t." + fieldName; //object数组 componentType获得object类型 ArrayTypeName arrayTypeName = (ArrayTypeName) ClassName.get(typeMirror); TypeElement typeElement = elementUtils.getTypeElement(arrayTypeName .componentType.toString()); //是否为 Parcelable 类型 if (!typeUtils.isSubtype(typeElement.asType(), parcelableType)) { throw new RuntimeException("Not Support Extra Type:" + typeMirror + " " + element); } statement = "$T[] " + fieldName + " = t.getIntent()" + ".getParcelableArrayExtra" + "($S)"; builder.addStatement(statement, parcelableType, extraName); builder.beginControlFlow("if( null != $L)", fieldName); statement = defaultValue + " = new $T[" + fieldName + ".length]"; builder.addStatement(statement, arrayTypeName.componentType) .beginControlFlow("for (int i = 0; i < " + fieldName + "" + ".length; " + "i++)") .addStatement(defaultValue + "[i] = ($T)" + fieldName + "[i]", arrayTypeName.componentType) .endControlFlow(); builder.endControlFlow(); return; } builder.addStatement(statement, extraName); }}复制代码

其实上面的注解处理器,会动态生成这样的一个类

public class Main2Activity$$Extra implements IExtra {  @Override  public void loadExtra(Object target) {    Main2Activity t = (Main2Activity)target;    t.path = t.getIntent().getStringExtra("path");  }}复制代码
  1. 通过一个API去加载这个类
public void loadExtra(Activity activity) {        String name = activity.getClass().getName();        IExtra iExtra = extraLruCache.get(name);        try {            if (iExtra == null) {                iExtra = (IExtra) Class.forName(activity.getClass().getName() + "$$Extra").getConstructor().newInstance();            }            iExtra.loadExtra(activity);            extraLruCache.put(name, iExtra);        } catch (Exception e) {            e.printStackTrace();        }    }复制代码
  1. 具体的调用实现
public class ModuleTest2Activity extends AppCompatActivity {    @Extra(name = "path")    public String url;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_module_test2);        PrimRouter.getInstance().inject(this);               TextView module2_textView = findViewById(R.id.module2_textView);//        Intent intent = getIntent();//        final String path = intent.getStringExtra("path");        module2_textView.setText("我是module2,我的地址是:/module2/test. 我是被地址:" + url + " 调起的");     }}复制代码

这样处理不仅大大提高了编码效率还减少了大量重复的代码,也提高了程序的可读性.

实现fragment的跳转

这里我们需要在原来的基础上,加几句代码。

//拿到fragment的全类名TypeElement fragment = elementUtils.getTypeElement(Consts.Fragment);        TypeElement v4Fragment = elementUtils.getTypeElement(Consts.V4Fragment);        //单个的节点        for (Element element : annotatedWith) {            // 获取类信息 如Activity类            TypeMirror typeMirror = element.asType();            // 获取节点的注解信息            Router annotation = element.getAnnotation(Router.class);            log.i(typeMirror + " | " + activity.asType());            //只能指定的类上面使用            if (typeUtils.isSubtype(typeMirror, activity.asType())) {                //存储路由相关的信息                routerMeta = new RouterMeta(RouterMeta.Type.ACTIVITY, annotation, element);            } else if (typeUtils.isSubtype(typeMirror, service.asType())) {                //存储路由相关的信息                routerMeta = new RouterMeta(RouterMeta.Type.SERVICE, annotation, element);            } else if (typeUtils.isSubtype(typeMirror, fragment.asType()) || typeUtils.isSubtype(typeMirror, v4Fragment.asType())) {                //存储路由相关的信息                routerMeta = new RouterMeta(RouterMeta.Type.FRAGMENT, annotation, element);            } else {                throw new RuntimeException("Just Support Activity Router!");            }            //检查是否配置group如果没有配置 则从path中截取组名            checkRouterGroup(routerMeta);        }复制代码

然后在我们的API库,返回fragment

case FRAGMENT:                Class
fragment = jumpCard.getDestination(); try { Object instance = fragment.getConstructor().newInstance(); if (instance instanceof Fragment) { ((Fragment) instance).setArguments(jumpCard.getExtras()); } else if (instance instanceof android.support.v4.app.Fragment) { ((android.support.v4.app.Fragment) instance).setArguments(jumpCard.getExtras()); } return instance; } catch (Exception e) { e.printStackTrace(); }复制代码

实现效果如下:

到此为止,我们的路由框架实现了以下功能: 支持直接解析标准URL路由地址进行跳转,并自动注入参数到目标页面中 支持多模块工程使用 支持模块间的通信 支持获取其他模块的fragment

Android的组件化专题:

转载地址:http://wavhl.baihongyu.com/

你可能感兴趣的文章
sqoop内部结构
查看>>
MySQL5.7 切不要"乱射" --transaction-write-set-extraction=MURMUR32
查看>>
ip tcp udp首部
查看>>
C#中文件操作类FileUtil
查看>>
前端知识点
查看>>
安装并配置基于虚拟用户的vsftpd
查看>>
Activity间用Intent和Bundle传递参数
查看>>
【C1】scala入门
查看>>
http请求状态码和请求信息的含义
查看>>
关于假设检验
查看>>
MapReduce原理(分布式计算模型)----------总结
查看>>
Linux学习笔记(九)--命令学习(文件与目录查看)
查看>>
2013最新Ghost Windows 7硬盘安装法详细(图文)教程
查看>>
centos6.5 安装mysql5.6多实例(多配置文件)
查看>>
Redis配置文件主要功能说明
查看>>
为什么要"去IOE"
查看>>
ubuntu 12.04安装mongodb+eclipse erlang plugin+erlang runtime
查看>>
arm-linux-gcc4.4.3编译s3c2410平台linux内核
查看>>
gitlab服务器
查看>>
我的友情链接
查看>>