Arouter与dagger2 mvp结合的一些实际问题

本文探讨了基于Dagger2的MVP架构项目中使用ARouter进行参数传递的问题。当使用@Autowired注解时,只有View层的参数能正确传递。文章深入分析了ARouter的源码,发现了参数类型未能正确注册的问题,并提供了详细的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

项目的架构为基于dagger2的mvp架构。在引入Arouter的时候发现只有在View层加入类@Autowired注解,参数才能正常传递。 如下代码:

String url="https://m.aliyun.com/test/activity1?name=老王&url=test&age=23&boy=true&high=180";
ARouter.getInstance().build(uri).navigation(this);
复制代码
@Route(path = "/test/activity1")
public class Test1Activity extends AppCompatActivity {
    @Inject
    Test1Contract.IPresenter presenter;
    
    @Autowired
    String name;

    @Autowired
    int age;

    @Autowired(name = "boy")
    boolean girl;

    @Autowired
    int high;
}

public interface Test1Contract{
    interface IPresenter{
        void test();
    }
}

public class Test1Presenter implements Test1Contract.IPresenter{
    @Autowired(name = "url")
    String url;
}

复制代码

getIntent()中存在age,name,high参数,却没有url参数。

发现问题

查阅Arouter源码,发现在LogisticsCenter类中

public synchronized static void completion(Postcard postcard) {
   ....
  if (MapUtils.isNotEmpty(paramsType)) {
      // Set value by its type, just for params which annotation by @Param
      for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
        setValue(postcard,
        params.getValue(),
        params.getKey(),
        resultMap.get(params.getKey()));
       }
       // Save params name which need autoinject.
        postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{})); }
    ...
}
复制代码

只有在RouterMap中的RouteMeta的parmType中有相应的参数类型时才会在Postcard中设置值,否则不会设置值。

查看build/generated/source/apt/debug/com/alibaba/android/arouter/routes/下生成的ARouter$$Group$$test,确实只生成了name,boy,age的参数类型,却未生成url的参数类型。

public class ARouter$$Group$$test implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test",
    new java.util.HashMap<String, Integer>(){{put("name", 8); put("boy", 0); put("age", 3); }}, -1, -2147483648));
  }
}
复制代码

所生成的代码中并未包含参数url的类型。 继续查阅compiler中的RouteProcessor源码

private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
 ...
 // Get all fields annotation by @Autowired
   if (types.isSubtype(tm, type_Activity)) {// Activity
       logger.info(">>> Found activity route: " + tm.toString() + " <<<");
       Map<String, Integer> paramsType = new HashMap<>();
       for (Element field : element.getEnclosedElements()) {
          if (field.getKind().isField() && field.getAnnotation(Autowired.class) != null && !types.isSubtype(field.asType(), iProvider)) {
             // It must be field, then it has annotation, but it not be provider.
             Autowired paramConfig = field.getAnnotation(Autowired.class);
             paramsType.put(StringUtils.isEmpty(paramConfig.name()) ? field.getSimpleName().toString() : paramConfig.name(), typeUtils.typeExchange(field));
       }
   }
  ...
}
复制代码

只有activity类型的router会自动解析字段中的@Autowired注解,并在RouteMeta中加入paramType的map。所以要继续使用arouter并能正确的接收参数只需要生成的RouteMeta中生成paramType就可以了。

开始操刀

由于项目中的变量都定义在presenter层,所以可以只要解析presenter中的变量即可。

问题一

presenter也是通过接口的方式注入。还需要反向找到具体的实现类。由于通过DeclaredType无法取到这个interface的具体实现类,所以暂时只能通过遍历的方式找到。

 public Set<? extends Element> getElementsWithInterface(Element var1) {
        if (var1.getKind() == INTERFACE) {
            throw new IllegalArgumentException("The element is not a interface type");
        } else {
            Set var2 = Collections.emptySet();
            TypeMirror typeMirror = var1.asType();
            InterfaceSetScanner var3 = new InterfaceSetScanner(var2);
            Element var5;
            for (Iterator var4 = this.rootElements.iterator(); var4.hasNext(); var2 = var3.scan(var5, typeMirror)) {
                var5 = (Element) var4.next();
            }
            return var2;
        }
    }
复制代码
问题二

若存在fragment等没有通过@Inject注入的方式的,也需要查找参数,所以重新定义了两个注解@ParamName,@AutoSetParams。 通过递归遍历这个activity的所有的@AutoSetParams和@Inject的具体实现类中的所有@ParamName注解的变量来查找paramType

private void findParams(Map<String, Integer> paramsTypeMap, Element element) {
        ElementKind kind = element.getKind();
        if (kind == ElementKind.FIELD) {
            ParamName paramConfig = element.getAnnotation(ParamName.class);
            if (paramConfig != null) {//有ParamName则
                String paramName = StringUtils.isEmpty(paramConfig.value()) ? element.getSimpleName().toString()
                        : paramConfig.value();
                paramsTypeMap.put(paramName, typeUtils.typeExchange(element));

                return;
            }
            if (element.getAnnotation(Inject.class) != null || element.getAnnotation(AutoSetParams.class) != null) {
                Object typeObject = element.asType();
                if (typeObject instanceof DeclaredType) {
                    DeclaredType declaredType = (DeclaredType) typeObject;
                    findParams(paramsTypeMap, declaredType.asElement());
                }
            }
        } else if (kind == ElementKind.CLASS) {
            
            TypeElement typeElement1 = (TypeElement) element;
            for (Element clsElement : typeElement1.getEnclosedElements()) {
                if (clsElement.getAnnotation(Inject.class) != null || clsElement.getAnnotation(AutoSetParams.class) != null) {
                
                    findParams(paramsTypeMap, clsElement);
                }
            }
            TypeMirror superclass = typeElement1.getSuperclass();
            TypeElement superElement = elements.getTypeElement(superclass.toString());
            if (superElement != null) {
                
                findParams(paramsTypeMap, superElement);
            }
        } else if (kind == ElementKind.INTERFACE) {
            Set<? extends Element> result = interfaceRoundEnvironment.getElementsWithInterface(element);
            
            for (Element clsElement : result) {
                findParams(paramsTypeMap, clsElement);
            }
        }
    }
复制代码

转载于:https://juejin.im/post/5aa79faaf265da2397068899

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值