背景
项目的架构为基于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);
}
}
}
复制代码