上一篇APT跳转已经完成,这一篇开始处理传值和封装跳转。首先来进行传值的封装。
我们参考下butterknife:
在Activity的onCreate()使用ButterKnife.bind(this);
在bind方法中会执行findBindingConstructorForClass()方法,在改方法中会拼接生成MainActivity_ViewBinding,最终赋值。
@UiThread
public MainActivity_ViewBinding(MainActivity target, View source) {
this.target = target;
target.bottomView = Utils.findRequiredViewAsType(source, R.id.bottom_view, "field 'bottomView'", BottomNavigationView.class);
target.tv_iknow = Utils.findRequiredViewAsType(source, R.id.tv_iknow, "field 'tv_iknow'", TextView.class);
target.layout_shadow = Utils.findRequiredView(source, R.id.layout_shadow, "field 'layout_shadow'");
}
我们可以参考butterKnife来进行传值,生成类似于MainActivity_ViewBinding的类然后进行赋值,先看一我们想要达到的效果
public class NextActivity$$Parameter implements ParameterData {
@Override
public void getParameter(Object targetParameter) {
NextActivity t = (NextActivity)targetParameter;
t.numberId = t.getIntent().getStringExtra("numberId");
t.name = t.getIntent().getStringExtra("name");
t.age = t.getIntent().getIntExtra("age", t.age);
}
}
开始撸码
1、先定义注解
@Target(ElementType.FIELD)//
@Retention(RetentionPolicy.CLASS)
public @interface Parameter {
String name() default "";
}
2、在自己module中使用
@ARouter(path = "/user/User_LoginAcitivty")
public class User_LoginAcitivty extends AppCompatActivity {
@Parameter
String numberId;
@Parameter
int age;
@Parameter
UserBean userBean;
@Parameter
List<String> data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_login_layout);
3、定义ParameterProcessor实现AbstractProcessor生成XXXX$$Parameter
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes(ProcessorConfig.PARAMETER_PACKAGE)
public class ParameterProcessor extends AbstractProcessor {
进行初始化
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
elementTool = processingEnvironment.getElementUtils();
filer = processingEnvironment.getFiler();
messager = processingEnvironment.getMessager();
typeTool = processingEnvironment.getTypeUtils();
}
在process方法中生成文件
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (!ProcessorUtils.isEmpty(set)) {
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Parameter.class);
if (!elements.isEmpty()) {//注解式作用在变量上,所以集合里存放的是声明的变量
for (Element element : elements) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();//获取父节点 MainActivity
if (mParameterMap.containsKey(enclosingElement)) {
mParameterMap.get(enclosingElement).add(element);
} else {
List<Element> fieldsList = new ArrayList<>();
fieldsList.add(element);
mParameterMap.put(enclosingElement, fieldsList);
}
}
if (mParameterMap.isEmpty()) return true;
TypeElement activityType = elementTool.getTypeElement(ProcessorConfig.ACTIVITY_PACKAGE);
TypeElement parameterType = elementTool.getTypeElement(ProcessorConfig.AROUTER_AIP_PARAMETER_DATA);//com.htf.arouter_api.ParameterData
/**
* 生成方法
* @Override
* public void getParameter(Object targetParameter) {
*/
ParameterSpec parameterSpec = ParameterSpec.builder(TypeName.OBJECT, ProcessorConfig.PARAMETER_NAME).build();
/**
* 方法里的内容
*/
for (Map.Entry<TypeElement, List<Element>> entry : mParameterMap.entrySet()) {
TypeElement typeElement = entry.getKey();
//先判断是不是在Activity
if (!typeTool.isSubtype(typeElement.asType(), activityType.asType())) {
throw new RuntimeException("@Parameter注解目前仅限用于Activity类之上");
}
ClassName className = ClassName.get(typeElement);
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(ProcessorConfig.PARAMETER_METHOD_NAME)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addParameter(parameterSpec);
ParameterFactory parameterFactory = new ParameterFactory.Builder(methodBuilder)
.setClassName(className)
.setMessager(messager)
.setElementTool(elementTool)
.setTypeTool(typeTool)
.build();
parameterFactory.addFirstStatement();
for (Element element : entry.getValue()) {
parameterFactory.buildStatement(element);
}
/**
* 生成文件
*/
String finalClassName = typeElement.getSimpleName().toString() + ProcessorConfig.PARAMETER_FILE_NAME;
try {
JavaFile.builder(className.packageName(),
TypeSpec.classBuilder(finalClassName)
.addSuperinterface(ClassName.get(parameterType))
.addModifiers(Modifier.PUBLIC)
.addMethod(parameterFactory.build())
.build())
.build()
.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return false;
}
先进行Parameter扫描,获取父节点然后判断添加,先写方法,再写内容,最后生成类文件,ParameterFactory使我们封装的用于添加内容的类,设计为构建者模式方便链式调用。
public class ParameterFactory {
// 方法的构建
private MethodSpec.Builder methodBuilder;
private Messager messager;
private ClassName className;// 类名,如:MainActivity
private Types typeTool;
private Elements elementTool; // 类信息
private ParameterFactory(Builder builder) {
this.messager = builder.messager;
this.className = builder.className;
this.typeTool = builder.typeTool;
this.elementTool = builder.elementTool;
this.methodBuilder = builder.methodBuilder;
}
public void addFirstStatement() {
methodBuilder.addStatement("$T t = ($T)" + ProcessorConfig.PARAMETER_NAME, className, className);
}
public void buildStatement(Element element) {
TypeMirror parcelableType = elementTool.getTypeElement(ProcessorConfig.PARCELABLE).asType();// //判断是不是对象bean类型
TypeMirror typeMirror = element.asType();//遍历注解的属性节点, 生成函数体
int type = typeMirror.getKind().ordinal();//获取TypeKind枚举的序列号
String fieldName = element.getSimpleName().toString();//获取属性名字 numberId 、name等
String annotationValue = element.getAnnotation(Parameter.class).name();//获取注解值
annotationValue = ProcessorUtils.isEmpty(annotationValue) ? fieldName : annotationValue;
String finalValue = "t." + fieldName;
String methodContent = finalValue + " = t.getIntent().";
// TypeKind 枚举类型不包含String
if (type == TypeKind.INT.ordinal()) {
methodContent += "getIntExtra($S, " + finalValue + ")"; // Int有默认值
} else if (type == TypeKind.DOUBLE.ordinal()) {
methodContent += "getDoubleExtra($S, " + finalValue + ")"; // Double有默认值
} else if (type == TypeKind.BOOLEAN.ordinal()) {
methodContent += "getBooleanExtra($S, " + finalValue + ")"; // Boolean有默认值
} else if (typeTool.isSubtype(typeMirror, parcelableType)) {
methodContent += "getParcelableExtra($S)"; // 没有默认值
} else if (typeMirror.toString().equals(ProcessorConfig.STRING)) {
methodContent += "getStringExtra($S)"; // 没有默认值
} else if (typeMirror.toString().equals(ProcessorConfig.LIST_STRING)) {
methodContent += "getStringArrayListExtra($S)"; // 没有默认值
} else {
messager.printMessage(Diagnostic.Kind.ERROR, "目前暂支持String、int、boolean、List<String>、对象bean传参");
}
methodBuilder.addStatement(methodContent, annotationValue);
}
public MethodSpec build() {
return methodBuilder.build();
}
/**
* Builder构建者设计模式
*/
public static class Builder {
private Messager messager;
private MethodSpec.Builder methodBuilder;
private ClassName className;
private Types typeTool;
private Elements elementTool;
public Builder(MethodSpec.Builder methodBuilder) {
this.methodBuilder = methodBuilder;
}
public Builder setElementTool(Elements elementTool) {
this.elementTool = elementTool;
return this;
}
public Builder setTypeTool(Types typeTool) {
this.typeTool = typeTool;
return this;
}
public Builder setMessager(Messager messager) {
this.messager = messager;
return this;
}
public Builder setClassName(ClassName className) {
this.className = className;
return this;
}
public ParameterFactory build() {
if (methodBuilder == null) {
throw new IllegalArgumentException("方法为空");
}
if (messager == null) {
throw new IllegalArgumentException("messager为空,Messager用来报告错误、警告和其他提示信息");
}
return new ParameterFactory(this);
}
}
在buildStatement方法中生成getIntent,build一下生成文件。
public class NextActivity$$Parameter implements ParameterData {
@Override
public void getParameter(Object targetParameter) {
NextActivity t = (NextActivity)targetParameter;
t.numberId = t.getIntent().getStringExtra("numberId");
t.name = t.getIntent().getStringExtra("name");
t.age = t.getIntent().getIntExtra("age", t.age);
}
}
4、接收参数,封装一个管理类ParameterManager,用于给带Parameter注解的变量赋值
public class ParameterManager {
private static ParameterManager instance;
public static ParameterManager getInstance() {
if (instance == null) {
synchronized (ParameterManager.class) {
if (instance == null) {
instance = new ParameterManager();
}
}
}
return instance;
}
// 为了寻找javapoet生成的User_LoginActivity + $$Parameter
static final String FILE_SUFFIX_NAME = "$$Parameter";
private LruCache<String, ParameterData> cache;
private ParameterManager() {
cache = new LruCache<>(100);//为了提高性能
}
public void loadParameter(Activity activity) {
String activityName = activity.getClass().getName();
ParameterData parameterData = cache.get(activityName);
if (parameterData == null) {
try {
Class<?> aClass = Class.forName(activityName + FILE_SUFFIX_NAME);
parameterData = (ParameterData) aClass.newInstance();
cache.put(activityName, parameterData);
} catch (Exception e) {
e.printStackTrace();
}
}
parameterData.getParameter(activity);
}
5、实现跳转的封装和携带数据。封装一个路由类RouterManager
public class RouterManager {
private String group;
private String path;
private static RouterManager instance;
private LruCache<String, ARouterGroup> mGroupLruCache;
private LruCache<String, ARouterPath> mPathLruCache;
public static RouterManager getInstance() {
if (instance == null) {
synchronized (RouterManager.class) {
if (instance == null) {
instance = new RouterManager();
}
}
}
return instance;
}
private RouterManager() {
mGroupLruCache = new LruCache<>(100);
mPathLruCache = new LruCache<>(100);
}
}
mGroupLruCache、mPathLruCache存储group和path通过下面的build方法获取跳转的activity
public BundleManager build(String path) {
if (TextUtils.isEmpty(path) || !path.startsWith("/")) {
throw new IllegalArgumentException("path错误,正确写法:如/user/User_LoginActivity");
}
if (path.lastIndexOf("/") == 0) {
throw new IllegalArgumentException("path错误,正确写法:如/user/User_LoginActivity");
}
// 截取组名 /user/User_LoginActivity finalGroup = user
String finalGroup = path.substring(1, path.indexOf("/", 1));
if (TextUtils.isEmpty(finalGroup)) {
throw new IllegalArgumentException("path错误,正确写法:如/user/User_LoginActivity");
}
this.path = path;
this.group = finalGroup;
return new BundleManager();
}
BundleManager是我们创建的传递数据的管理类,Activity传递数据,底层都是Bundle,所以返回一个Bundle对象为了我们链式调用传递数据
public class BundleManager {
private Bundle mBundle = new Bundle();
public Bundle getBundle() {
return mBundle;
}
// 对外界提供,可以携带参数的方法链式调用效果 模仿开源框架
public BundleManager withString(@NonNull String key, @Nullable String value) {
mBundle.putString(key, value);
return this;
}
public BundleManager withDouble(@NonNull String key, @Nullable double value) {
mBundle.putDouble(key, value);
return this;
}
public BundleManager withBoolean(@NonNull String key, @Nullable boolean value) {
mBundle.putBoolean(key, value);
return this;
}
public BundleManager withParcelable(@NonNull String key, @Nullable Parcelable value) {
mBundle.putParcelable(key, value);
return this;
}
public BundleManager withSerializable(@NonNull String key, @Nullable Serializable value) {
mBundle.putSerializable(key, value);
return this;
}
public BundleManager withInt(@NonNull String key, @Nullable int value) {
mBundle.putInt(key, value);
return this;
}
public BundleManager withStringArrayListExtra(@NonNull String key, @Nullable List<String> value) {
mBundle.putStringArrayList(key, (ArrayList<String>) value);
return this;
}
public BundleManager withBundle(Bundle bundle) {
this.mBundle = bundle;
return this;
}
public Object navigation(Context context) {
return RouterManager.getInstance().navigation(context, this);
}
public Object navigation(Context context, int requestCode) {
return RouterManager.getInstance().navigation(context, this, requestCode);
}
}
navagation调用RouterManager里的navigation方法最终实现跳转。
// 例如:寻找 ARouter$$Group$$user 寻址 ARouter$$Group$$user ARouter$$Group$$app
public Object navigation(Context context, BundleManager bundleManager) {
RouterBean routerBean = getRouterBean(context);
if (routerBean != null) {
switch (routerBean.getTypeEnum()) {//为了区别Fragment Activity
case ACTIVITY:
Intent intent = new Intent(context, routerBean.getMyClass()); // 例如:getClazz == Order_MainActivity.class
intent.putExtras(bundleManager.getBundle()); // 携带参数
context.startActivity(intent);
break;
}
}
return null;
}
public Object navigation(Context context, BundleManager bundleManager, int requestCode) {
RouterBean routerBean = getRouterBean(context);
if (routerBean != null) {
switch (routerBean.getTypeEnum()) {//为了区别Fragment Activity
case ACTIVITY:
Intent intent = new Intent(context, routerBean.getMyClass()); // 例如:getClazz == Order_MainActivity.class
intent.putExtras(bundleManager.getBundle()); // 携带参数
((Activity) context).startActivityForResult(intent, requestCode);
break;
}
}
return null;
}
6、项目中实现调用:
@ARouter(path = "/zixun/ZiXun_WebViewActivity")
public class ZiXun_WebViewActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.zixun_webview_layout);
}
public void jumpLogin(View view) {
List<String> data = new ArrayList<>();
data.add("biubiubiu");
data.add("男男女女多所军军");
RouterManager.getInstance().build("/user/User_LoginAcitivty")
.withStringArrayListExtra("data", data)
.navigation(this);
}
}
在User_LoginAcitivty 通过ParameterManager.getInstance().loadParameter(this);接收数据
@ARouter(path = "/user/User_LoginAcitivty")
public class User_LoginAcitivty extends AppCompatActivity {
@Parameter
List<String> data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_login_layout);
ParameterManager.getInstance().loadParameter(this);
for (String sss : data) {
Log.e("TAG", sss);
}
}
这样就完成了数据的传递和Activity的跳转。
项目地址
项目中用到的都是最基本的技术,基本上不会遇到适配问题。不过需要对注解和反射有所了解。