依赖注入部分
依赖注入的注解@Autowired,有三个参数,其中第二个时候为必需参数,如果注解的时候加入了此参数传值的时候就一定得传入此参数,否则会直接crash
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Autowired {
// Mark param's name or service name.
String name() default "";
// If required, app will be crash when value is null.
// Primitive type wont be check!
boolean required() default false;
// Description of the field
String desc() default "";
}
被注解的示例类:
@Route(path = "/test/activity1", name = "测试用 Activity")
public class Test1Activity extends BaseActivity {
@Autowired
int age = 10;
@Autowired
int height = 175;
@Autowired(name = "boy", required = true)
boolean girl;
@Autowired
char ch = 'A';
@Autowired
float fl = 12.00f;
@Autowired
double dou = 12.01d;
@Autowired
TestSerializable ser;
@Autowired
TestParcelable pac;
@Autowired
TestObj obj;
@Autowired
List<TestObj> objList;
@Autowired
Map<String, List<TestObj>> map;
private long high;
@Autowired
String url;
@Autowired
HelloService helloService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
ARouter.getInstance().inject(this);
String params = String.format("name=%s,\n age=%s, \n height=%s,\n girl=%s,\n high=%s,\n url=%s,\n ser=%s,\n pac=%s,\n obj=%s \n ch=%s \n fl = %s, \n dou = %s, \n objList=%s, \n map=%s", name, age, height, girl, high, url, ser, pac, obj, ch, fl, dou, objList, map);
helloService.sayHello("Hello moto.");
((TextView) findViewById(R.id.test)).setText("I am " + Test1Activity.class.getName());
((TextView) findViewById(R.id.test2)).setText(params);
}
}
@Autowired的注解处理器
@AutoService(Processor.class)
@SupportedAnnotationTypes({ANNOTATION_TYPE_AUTOWIRED})
public class AutowiredProcessor extends BaseProcessor {
private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>(); // Contain field need autowired and his super class.
private static final ClassName ARouterClass = ClassName.get("com.alibaba.android.arouter.launcher", "ARouter");
private static final ClassName AndroidLog = ClassName.get("android.util", "Log");
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (CollectionUtils.isNotEmpty(set)) {
try {
categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
generateHelper();
} catch (Exception e) {
logger.error(e);
}
return true;
}
return false;
}
private void generateHelper() throws IOException, IllegalAccessException {
TypeElement type_ISyringe = elementUtils.getTypeElement(ISYRINGE);
TypeElement type_JsonService = elementUtils.getTypeElement(JSON_SERVICE);
TypeMirror iProvider = elementUtils.getTypeElement(Consts.IPROVIDER).asType();
TypeMirror activityTm = elementUtils.getTypeElement(Consts.ACTIVITY).asType();
TypeMirror fragmentTm = elementUtils.getTypeElement(Consts.FRAGMENT).asType();
TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType();
// Build input param name.
ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();
if (MapUtils.isNotEmpty(parentAndChild)) {
//遍历parentAndChild里面所有的key-value集合
for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
//构造inject方法
MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
.addAnnotation(Override.class)
.addModifiers(PUBLIC)
.addParameter(objectParamSpec);
//取出entry里面的TypeElement,也就是完整的类名
//com.alibaba.android.arouter.demo.module1.testactivity.Test1Activity
TypeElement parent = entry.getKey();
//取出entry里面的childs,也就是这个类下被@Autowired注解的所有的变量
List<Element> childs = entry.getValue();
// com.alibaba.android.arouter.demo.module1.testactivity.Test1Activity
String qualifiedName = parent.getQualifiedName().toString();
//com.alibaba.android.arouter.demo.module1.testactivity
String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
//Test1Activity$$ARouter$$Autowired
String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;
logger.info(">>> Start process " + childs.size() + " field in " + parent.getSimpleName() + " ... <<<");
//构建类名
//public class Test1Activity$$ARouter$$Autowired implements ISyringe
TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
.addJavadoc(WARNING_TIPS)
.addSuperinterface(ClassName.get(type_ISyringe))
.addModifiers(PUBLIC);
//私有的成员变量
// private SerializationService serializationService;
FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
helper.addField(jsonServiceField);
//inject方法里添加代码
//serializationService = ARouter.getInstance().navigation(SerializationService.class);
injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class)", ARouterClass, ClassName.get(type_JsonService));
//inject方法里添加代码
//Test1Activity substitute = (Test1Activity)target;
injectMethodBuilder.addStatement("$T substitute = ($T)target", ClassName.get(parent), ClassName.get(parent));
// 遍历这个类下所有被@Autowired注解的变量
for (Element element : childs) {
Autowired fieldConfig = element.getAnnotation(Autowired.class);
String fieldName = element.getSimpleName().toString();
if (types.isSubtype(element.asType(), iProvider)) { // It's provider
if ("".equals(fieldConfig.name())) { // User has not set service path, then use byType.
// Getter
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
ARouterClass,
ClassName.get(element.asType())
);
} else { // use byName
// Getter
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation()",
ClassName.get(element.asType()),
ARouterClass,
fieldConfig.name()
);
}
// Validator
if (fieldConfig.required()) {
injectMethodBuilder.beginControlFlow("if (substitute." + fieldName + " == null)");
injectMethodBuilder.addStatement(
"throw new RuntimeException("The field '" + fieldName + "' is null, in class '" + $T.class.getName() + "!")", ClassName.get(parent));
injectMethodBuilder.endControlFlow();
}
} else { // It's normal intent value
String originalValue = "substitute." + fieldName;
String statement = "substitute." + fieldName + " = " + buildCastCode(element) + "substitute.";
boolean isActivity = false;
if (types.isSubtype(parent.asType(), activityTm)) { // Activity, then use getIntent()
isActivity = true;
statement += "getIntent().";
} else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) { // Fragment, then use getArguments()
statement += "getArguments().";
} else {
throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, its parent must be activity or fragment!");
}
statement = buildStatement(originalValue, statement, typeUtils.typeExchange(element), isActivity, isKtClass(parent));
if (statement.startsWith("serializationService.")) { // Not mortals
injectMethodBuilder.beginControlFlow("if (null != serializationService)");
injectMethodBuilder.addStatement(
"substitute." + fieldName + " = " + statement,
(StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name()),
ClassName.get(element.asType())
);
injectMethodBuilder.nextControlFlow("else");
injectMethodBuilder.addStatement(
"$T.e("" + Consts.TAG + "", "You want automatic inject the field '" + fieldName + "' in class '$T' , then you should implement 'SerializationService' to support object auto inject!")", AndroidLog, ClassName.get(parent));
injectMethodBuilder.endControlFlow();
} else {
injectMethodBuilder.addStatement(statement, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name());
}
// Validator
if (fieldConfig.required() && !element.asType().getKind().isPrimitive()) { // Primitive wont be check.
injectMethodBuilder.beginControlFlow("if (null == substitute." + fieldName + ")");
injectMethodBuilder.addStatement(
"$T.e("" + Consts.TAG + "", "The field '" + fieldName + "' is null, in class '" + $T.class.getName() + "!")", AndroidLog, ClassName.get(parent));
injectMethodBuilder.endControlFlow();
}
}
}
helper.addMethod(injectMethodBuilder.build());
// Generate autowire helper
JavaFile.builder(packageName, helper.build()).build().writeTo(mFiler);
logger.info(">>> " + parent.getSimpleName() + " has been processed, " + fileName + " has been generated. <<<");
}
logger.info(">>> Autowired processor stop. <<<");
}
}
private boolean isKtClass(Element element) {
for (AnnotationMirror annotationMirror : elementUtils.getAllAnnotationMirrors(element)) {
if (annotationMirror.getAnnotationType().toString().contains("kotlin")) {
return true;
}
}
return false;
}
private String buildCastCode(Element element) {
if (typeUtils.typeExchange(element) == TypeKind.SERIALIZABLE.ordinal()) {
return CodeBlock.builder().add("($T) ", ClassName.get(element.asType())).build().toString();
}
return "";
}
/**
* Build param inject statement
*/
private String buildStatement(String originalValue, String statement, int type, boolean isActivity, boolean isKt) {
switch (TypeKind.values()[type]) {
case BOOLEAN:
statement += "getBoolean" + (isActivity ? "Extra" : "") + "($S, " + originalValue + ")";
break;
case BYTE:
statement += "getByte" + (isActivity ? "Extra" : "") + "($S, " + originalValue + ")";
break;
case SHORT:
statement += "getShort" + (isActivity ? "Extra" : "") + "($S, " + originalValue + ")";
break;
case INT:
statement += "getInt" + (isActivity ? "Extra" : "") + "($S, " + originalValue + ")";
break;
case LONG:
statement += "getLong" + (isActivity ? "Extra" : "") + "($S, " + originalValue + ")";
break;
case CHAR:
statement += "getChar" + (isActivity ? "Extra" : "") + "($S, " + originalValue + ")";
break;
case FLOAT:
statement += "getFloat" + (isActivity ? "Extra" : "") + "($S, " + originalValue + ")";
break;
case DOUBLE:
statement += "getDouble" + (isActivity ? "Extra" : "") + "($S, " + originalValue + ")";
break;
case STRING:
statement += (isActivity ? ("getExtras() == null ? " + originalValue + " : substitute.getIntent().getExtras().getString($S") : ("getString($S")) + ", " + originalValue + ")";
break;
case SERIALIZABLE:
statement += (isActivity ? ("getSerializableExtra($S)") : ("getSerializable($S)"));
break;
case PARCELABLE:
statement += (isActivity ? ("getParcelableExtra($S)") : ("getParcelable($S)"));
break;
case OBJECT:
statement = "serializationService.parseObject(substitute." + (isActivity ? "getIntent()." : "getArguments().") + (isActivity ? "getStringExtra($S)" : "getString($S)") + ", new " + TYPE_WRAPPER + "<$T>(){}.getType())";
break;
}
return statement;
}
//扫描所有被@Autowired注解的变量element,如果是被private修饰则直接抛出异常
//找到这些变量所在的类 enclosingElement
//把这些变量按照其所在的类作为key的情况下,分类放在private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>();
private void categories(Set<? extends Element> elements) throws IllegalAccessException {
if (CollectionUtils.isNotEmpty(elements)) {
for (Element element : elements) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();//获取到这个element所在的类名
if (element.getModifiers().contains(Modifier.PRIVATE)) {
throw new IllegalAccessException("The inject fields CAN NOT BE 'private'!!! please check field ["
+ element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
}
if (parentAndChild.containsKey(enclosingElement)) { // Has categries
parentAndChild.get(enclosingElement).add(element);
} else {
List<Element> childs = new ArrayList<>();
childs.add(element);
parentAndChild.put(enclosingElement, childs);
}
}
logger.info("categories finished.");
}
}
}
被注解的类通过注解处理器生成的代码示例如下
public interface ISyringe {
void inject(Object target);
}
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class Test1Activity$$ARouter$$Autowired implements ISyringe {
private SerializationService serializationService;
@Override
public void inject(Object target) {
serializationService = ARouter.getInstance().navigation(SerializationService.class);
Test1Activity substitute = (Test1Activity)target;
substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
substitute.height = substitute.getIntent().getIntExtra("height", substitute.height);
substitute.girl = substitute.getIntent().getBooleanExtra("boy", substitute.girl);
substitute.ch = substitute.getIntent().getCharExtra("ch", substitute.ch);
substitute.fl = substitute.getIntent().getFloatExtra("fl", substitute.fl);
substitute.dou = substitute.getIntent().getDoubleExtra("dou", substitute.dou);
substitute.ser = (com.alibaba.android.arouter.demo.service.model.TestSerializable) substitute.getIntent().getSerializableExtra("ser");
substitute.pac = substitute.getIntent().getParcelableExtra("pac");
if (null != serializationService) {
substitute.obj = serializationService.parseObject(substitute.getIntent().getStringExtra("obj"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestObj>(){}.getType());
} else {
Log.e("ARouter::", "You want automatic inject the field 'obj' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
}
if (null != serializationService) {
substitute.objList = serializationService.parseObject(substitute.getIntent().getStringExtra("objList"), new com.alibaba.android.arouter.facade.model.TypeWrapper<List<TestObj>>(){}.getType());
} else {
Log.e("ARouter::", "You want automatic inject the field 'objList' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
}
if (null != serializationService) {
substitute.map = serializationService.parseObject(substitute.getIntent().getStringExtra("map"), new com.alibaba.android.arouter.facade.model.TypeWrapper<Map<String, List<TestObj>>>(){}.getType());
} else {
Log.e("ARouter::", "You want automatic inject the field 'map' in class 'Test1Activity' , then you should implement 'SerializationService' to support object auto inject!");
}
substitute.url = substitute.getIntent().getExtras() == null ? substitute.url : substitute.getIntent().getExtras().getString("url", substitute.url);
substitute.helloService = ARouter.getInstance().navigation(HelloService.class);
}
}
自动赋值操作(可以参考ButterKnife)
在示例的类的代码里onCreate()里面,调用了Arouter.getInstance().inject(this)来实现自动赋值操作。
@Route(path = "/test/activity1", name = "测试用 Activity")
public class Test1Activity extends BaseActivity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
ARouter.getInstance().inject(this);
((TextView) findViewById(R.id.test)).setText("I am " + Test1Activity.class.getName());
((TextView) findViewById(R.id.test2)).setText(params);
}
}
ARouter.java
public void inject(Object thiz) {
_ARouter.inject(thiz);
}
_ARouter.java
//通过注解的形式启动了AutewiredService的实现类
static void inject(Object thiz) {
AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());//在navigation里面会调用其init()函数,并返回一个实例赋值给autowiredService
if (null != autowiredService) {
autowiredService.autowire(thiz); //自动装载
}
}
被ARouter启动的AutowiredServiceImpl,在navigation里面会调用到其init函数,并返回一个实例对象赋值给autowiredService,可以参考上文的InterceptorServiceImpl一样的流程。
public interface AutowiredService extends IProvider {
void autowire(Object instance);
}
public interface IProvider {
void init(Context context);
}
@Route(path = "/arouter/service/autowired")
public class AutowiredServiceImpl implements AutowiredService {
private LruCache<String, ISyringe> classCache;
private List<String> blackList;
//初始化一个cache和一个blackList
@Override
public void init(Context context) {
classCache = new LruCache<>(50);
blackList = new ArrayList<>();
}
//自动注入,instance为调用ARouter.getInstance().inject(this);的类的对象
@Override
public void autowire(Object instance) {
doInject(instance, null);
}
private void doInject(Object instance, Class<?> parent) {
//class com.alibaba.android.arouter.demo.module1.testactivity.Test1Activity
Class<?> clazz = null == parent ? instance.getClass() : parent;
ISyringe syringe = getSyringe(clazz); //拿到clazz对应的辅助类
if (null != syringe) {
syringe.inject(instance); //调用辅助类的inject方法
}
//获取调用类的父类,如果父类里也有被@Autowired注解的变量,也会赋值
//class com.alibaba.android.arouter.demo.module1.testactivity.BaseActivity
//class android.support.v7.app.AppCompatActivity
Class<?> superClazz = clazz.getSuperclass();
// has parent and its not the class of framework.
if (null != superClazz && !superClazz.getName().startsWith("android")) {
doInject(instance, superClazz);
}
}
private ISyringe getSyringe(Class<?> clazz) {
String className = clazz.getName();
//com.alibaba.android.arouter.demo.module1.testactivity.Test1Activity
try {
//判断黑名单里是否有这个类
if (!blackList.contains(className)) {
//从init的cache中获取这个类,首次进入不存在
ISyringe syringeHelper = classCache.get(className);
if (null == syringeHelper) { // No cache.
//通过反射调用到这个类对应的生成的辅助类,实例化一个对话赋值给syringeHelper,并通过key-value的形式缓存到classCache里面
//com.alibaba.android.arouter.demo.module1.testactivity.Test1Activity$$ARouter$$Autowired
syringeHelper = (ISyringe) Class.forName(clazz.getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
}
classCache.put(className, syringeHelper);
return syringeHelper;
}
} catch (Exception e) {
blackList.add(className); // This instance need not autowired.
}
return null;
}
}
降级策略
单独降级策略和全局的降级策略都是在_Arouter的这个navigation里面实现的,主要
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
// Pretreatment failed, navigation canceled.
return null;
}
System.out.println("navigation" );
// Set context to postcard.
postcard.setContext(null == context ? mContext : context);
try {
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {、
//在补全postcard的时候,如果出现了没找到RouteMeta的情况,会catch这个异常
logger.warning(Consts.TAG, ex.getMessage());
//如果是debug版本,会有个Toast提示
if (debuggable()) {
runInMainThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, "There's no route matched!\n" +
" Path = [" + postcard.getPath() + "]\n" +
" Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
}
});
}
//如果在navigation的时候,有传入callback,及为这个跳转做单独的降级策略,单独的降级策略的优先级是高于全局降级策略的
if (null != callback) {
System.out.println("null != callback");
callback.onLost(postcard);
} else {
//如果在navigation的时候,没有传入callback,则会这个跳转做全局的降级策略
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
//这个单独的callback可以继续传递,找了对应的RuteMeta之后,找到了的回调
if (null != callback) {
callback.onFound(postcard);
}
if (!postcard.isGreenChannel()) {
interceptorService.doInterceptions(postcard, new InterceptorCallback() {
@Override
public void onContinue(Postcard postcard) {
_navigation(postcard, requestCode, callback);
}
//这个单独的callback可以继续传递,,如果有拦截器对这个navigation进行了拦截,还有拦截了的回调
@Override
public void onInterrupt(Throwable exception) {
if (null != callback) {
callback.onInterrupt(postcard);
}
}
} else {
System.out.println("postcard.isGreenChannel()");
return _navigation(postcard, requestCode, callback);
}
return null;
}
//这个callback继续传递
@SuppressLint("WrongConstant")
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
final Context currentContext = postcard.getContext();
System.out.println("_navigation getType : " + postcard.getType());
switch (postcard.getType()) {
case ACTIVITY:
...
// Navigation in main looper.
runInMainThread(new Runnable() {
@Override
public void run() {
startActivity(requestCode, currentContext, intent, postcard, callback);
}
});
break;
case PROVIDER:
return postcard.getProvider();
case BOARDCAST:
case CONTENT_PROVIDER:
case FRAGMENT:
...
case METHOD:
case SERVICE:
default:
return null;
}
return null;
}
private void startActivity(int requestCode, Context currentContext, Intent intent, Postcard postcard, NavigationCallback callback) {
if (requestCode >= 0) { // Need start for result
if (currentContext instanceof Activity) {
ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
} else {
logger.warning(Consts.TAG, "Must use [navigation(activity, ...)] to support [startActivityForResult]");
}
} else {
ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
}
if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version.
((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
}
//最后的完成了startActivity之后,还有个完成的回调
if (null != callback) { // Navigation over.
callback.onArrival(postcard);
}
}
单独降级
单独降级策略实现在navigation的时候实现其对应的接口即可。
ARouter.getInstance().build("/xxx/xxx").navigation(this, new NavCallback() {
@Override
public void onFound(Postcard postcard) {
Log.d("ARouter", "找到了");
}
@Override
public void onLost(Postcard postcard) {
Log.d("ARouter", "找不到了");
}
@Override
public void onArrival(Postcard postcard) {
Log.d("ARouter", "跳转完了");
}
@Override
public void onInterrupt(Postcard postcard) {
Log.d("ARouter", "被拦截了");
}
});
全局降级
全局的降级策略只提供了一个接口,并没有具体的实现类,业务需要需要自己实现对应的业务代码,并通过@Route注册
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
try {
LogisticsCenter.completion(postcard);
} catch (NoRouteFoundException ex) {
...
if (null != callback) {
System.out.println("null != callback");
callback.onLost(postcard);
} else {
//全局的降级策略
DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
if (null != degradeService) {
degradeService.onLost(context, postcard);
}
}
return null;
}
...
return null;
}
public interface DegradeService extends IProvider {
void onLost(Context context, Postcard postcard);
}
public interface IProvider {
void init(Context context);
}
业务对全局降级策略的实现
@Route(path = "/degrade/test")
public class DegradeServiceImpl implements DegradeService {
@Override
public void onLost(Context context, Postcard postcard) {
Log.e("DegradeServiceImpl", "DegradeServiceImpl onLost");
}
@Override
public void init(Context context) {
Log.e("DegradeServiceImpl", "DegradeServiceImpl init");
}
}