上几篇组件化专题文章,我们对路由框架基本实现了,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,通过一个注解就可以拿到跳转传递过来的参数的值,然后直接使用。
@Extra
public String path;
那么我们如何实现呢? 其实很简单,我们通过注解拿到父类Activity,然后注解变量的类型和名称,然后我们动态生成一个类,通过原生的方式来实现参数获取。
其实跟上几篇的文章是一样的原理,这里就不再多复述了这是链接组件化专题
下面就直接一堆代码,抛给你
- 首先声明注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS)
public @interface Extra {
String name() default "";
}
- 注解处理器处理注解,这里面的逻辑其实非常简单,主要是看你对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<TypeElement, List<Element>> 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<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (null != set && !set.isEmpty()) {//注意这里必须要判断set.isEmpty() 否则会走两遍
log.i("process");
//拿到注有Extra 的节点集合
Set<? extends Element> 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<? extends Element> elementsAnnotatedWith) {
for (Element element : elementsAnnotatedWith) {
//获取注解父类的节点类型
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
if (extraMap.containsKey(enclosingElement)) {
extraMap.get(enclosingElement).add(element);
} else {
List<Element> 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<TypeElement, List<Element>> 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<TypeElement, List<Element>> 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<TypeElement, List<Element>> 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<TypeName> 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");
}
}
- 通过一个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();
}
}
- 具体的调用实现
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();
}
实现效果如下:
image.png到此为止,我们的路由框架实现了以下功能:
支持直接解析标准URL路由地址进行跳转,并自动注入参数到目标页面中
支持多模块工程使用
支持模块间的通信
支持获取其他模块的fragment
Android的组件化专题:
组件化配置
网友评论