完整組化件和插件化可以參考我的github項目,已經用在線上項目中
上面三篇文章我們已經瞭解了組件化的原理和一些跳轉思路,下面我們就一步一步來搭建我們的組件化架構.
首先是環境的搭建,可以參考上面三篇文章
其次是搭建apt環境
1: 創建一個java模塊compile,配置相應依賴,下面是配置
import javax.tools.JavaCompiler
apply plugin: 'java-library'
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
implementation 'com.squareup:javapoet:1.9.0'
implementation project(':ancely_annotation')
}
tasks.withType(JavaCompiler) {
options.encoding = 'UTF-8'
}
sourceCompatibility = "7"
targetCompatibility = "7"
2,創建一個類AncelyProcess繼承AbstractProcessor,生成代碼邏輯主要在這個類裏面
3, 再創建一個類生成的註解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface ARouter {
String path();
String group() default "";
}
4, 再創建一個RouterBean,保存了所有還有@ARouter註解的類的一些信息
public class RouteBean {
public enum Type {
ACTIVITY, CALL, FRAGMENT_V4
}
//枚舉類型
private Type type;
//類節點
private Element element;
//被ARoute註解的對象
private Class<?> clazz;
//路由的組名
private String group;
//路由的地址
private String path;
}
5,最後我們要生成的二個類的形式爲下面,每一個Model裏面如果有就會在每個Model下生成對應的二個類文件,生成下面二個類的代碼就不介紹,生成順序爲先生成ARoute$$Path$$app,然後再生成ARoute$$Group$$app,因爲我們要將ARoute$$Path$$app這個類對應到我們的組裏去
想要看完整生成代碼的邏輯,可以去我github上
public class ARoute$$Path$$app implements ARouteLoadPath {
@Override
public Map<String, RouteBean> loadPath() {
Map<String,RouteBean> pathMap = new HashMap<>();
pathMap.put("/app/TextModelActivity",RouteBean.create(RouteBean.Type.ACTIVITY,TextModelActivity.class,"/app/TextModelActivity","app"));
pathMap.put("/app/TextFragment",RouteBean.create(RouteBean.Type.FRAGMENT_V4,TextFragment.class,"/app/TextFragment","app"));
pathMap.put("/app/MainActivity",RouteBean.create(RouteBean.Type.ACTIVITY,MainActivity.class,"/app/MainActivity","app"));
return pathMap;
}
}
public class ARoute$$Group$$app implements ARouteLoadGroup {
@Override
public Map<String, Class<? extends ARouteLoadPath>> loadGroup() {
Map<String,Class<? extends ARouteLoadPath>> groupMap = new HashMap<>();
groupMap.put("app",ARoute$$Path$$app.class);
return groupMap;
}
}
類生成完了也就是相應的路由都配置好,這樣就開始做路由的管理,也就是界面相互跳轉相互傳參的操作,新建路由管理類RouterManager
public class RouterManager {
private String mGroup;
private String mPath;
private static RouterManager sInstance;
private LruCache<String, ARouteLoadGroup> mGroupLruCache; //組緩存
private LruCache<String, ARouteLoadPath> mPathLruCache; // 跳轉地址緩存
private static final String GROUP_FILE_PREFFIX_NAME = "ARoute$$Group$$";
private RouterManager() {
mGroupLruCache = new LruCache<>(163);//最大條目爲163
mPathLruCache = new LruCache<>(163);//最大條目爲163
}
public static RouterManager getInstance() {
if (sInstance == null) {
synchronized (RouterManager.class) {
if (sInstance == null) {
sInstance = new RouterManager();
}
}
}
return sInstance;
}
}
從上面幾個成員變量可以看出來,我們對組和組對應的pah做了相應的緩存,將獲取到的組,我組對應的path添加到相應緩存的代碼如下
public Object navigation(Context context, BundleManager bundleManager, int code) {
if (bundleManager.isFinish()) {
Intent intent = new Intent();
if ((bundleManager.getBundle() != null)) intent.putExtras(bundleManager.getBundle());
((Activity) context).setResult(code, intent);
((Activity) context).finish();
return null;
}
//獲取對應組類文件的全類名比如com.ancely.fyw.modular.apt.ARoute$$Group$$app
String groupClassName = "com.ancely.fyw.modular.apt." + GROUP_FILE_PREFFIX_NAME + mGroup;
Log.e("ancely>>> :", groupClassName);
try {
//讀取group的類文件 懶加載方式 如果只打開app只只加載app裏的
ARouteLoadGroup loadGroup = mGroupLruCache.get(mGroup);
if (loadGroup == null) {
//加載APT groutp類文件 如: ARouter$$Group$$app
Class<?> clazz = Class.forName(groupClassName);
loadGroup = (ARouteLoadGroup) clazz.newInstance();
//添加到緩存裏
mGroupLruCache.put(mGroup, loadGroup);
}
//判空
if (loadGroup.loadGroup().isEmpty()) {
throw new RuntimeException("arouter group 加載失敗");
}
//讀取path
ARouteLoadPath loadPath = mPathLruCache.get(mPath);
if (loadPath == null) {
//通過group加載接口,去獲取path加載接口
Class<? extends ARouteLoadPath> clazz = loadGroup.loadGroup().get(mGroup);
if (clazz != null) loadPath = clazz.newInstance();
if (loadPath != null) mPathLruCache.put(mPath, loadPath);
}
if (loadPath != null) {
if (loadPath.loadPath().isEmpty()) {
throw new RuntimeException("arouter path 加載失敗");
}
RouteBean routeBean = loadPath.loadPath().get(mPath);
if (routeBean != null) {
//類型判斷
switch (routeBean.getType()) {
case ACTIVITY:
Intent intent = new Intent(context, routeBean.getClazz());
intent.putExtras(bundleManager.getBundle());
if (bundleManager.isResult()) {
((Activity) context).setResult(code, intent);
}
if (code > 0) {//跳轉的時候需要回調
((Activity) context).startActivityForResult(intent, code, bundleManager.getBundle());
} else {
context.startActivity(intent, bundleManager.getBundle());
}
break;
case CALL:
//返回的是一個接口的實現類
return routeBean.getClazz().newInstance();
case FRAGMENT_V4:
Fragment fragment = (Fragment) routeBean.getClazz().newInstance();
fragment.setArguments(bundleManager.getBundle());
return fragment;
default:
break;
}
} else {
Toast.makeText(context, "功能暫未開放", Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
這樣我們就可以直接使用了
RouterManager.getInstance().build("/login/Login_MainActivity1").xxx.
.navigation(this, 20);就可以完成跳轉