1.使用:
1.添加依赖:
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
}
dependencies {
implementation 'com.alibaba:arouter-api:1.5.0'
annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'
...
}
2.在Application中初始化:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
ARouter.openDebug(); //调试模式下必须开启Debug,否则页面无法正常跳转
ARouter.openLog();
ARouter.printStackTrace();
}
ARouter.init(MyApplication.this);
}
}
3.在第一个Activity启动时初始化:
protected void onCreate(Bundle savedInstanceState) {
@Override
protected void onCreate(Bundle savedInstanceState) {
ARouter.getInstance().inject(this);
}
}
4.给目标组件类添加注解定义其url:
// 这里的路径是必选项,且这里的路径需要注意的是至少需要有两级,/xx/xx
@Route(path = "/test/testActivity")
public class TestActivity extends AppCompatActivity {
//1.通过Autowired注解表明key 2.需要在onCreate中调用ARouter.getInstance().inject(this);
@Autowired(name = "param1")
public long data;
//2.通过Autowired注解表明key 2.将param1作为属性的名称 3.需要在onCreate中调用ARouter.getInstance().inject(this);
@Autowired()
public long param1;
//3.通过Bundle获取
getIntent().getExtras().getLong("param1")
}
4.跳转:
//简单跳转
ARouter.getInstance().build("/test/testActivity").navigation();
//带参数跳转
ARouter.getInstance().build("/test/testActivity")
.withLong("param1", 100L)
.withString("param2", "mac")
.withSerializable("param3", new Student("Jack", 18))
.navigation();
向其他模块传递自定义类型:
@Route(path = "/custom/json")
public class JsonSerializationService implements SerializationService {
Gson gson;
@Override
public <T> T json2Object(String input, Class<T> clazz) {
return gson.fromJson(input,clazz);
}
@Override
public String object2Json(Object instance) {
return gson.toJson(instance);
}
@Override
public <T> T parseObject(String input, Type clazz) {
return gson.fromJson(input,clazz);
}
@Override
public void init(Context context) {
gson = new Gson();
}
}
用SerializationService 获取自定义类型
User obj = serializationService.parseObject(getIntent().getStringExtra("key4"), User.class);
其他功能参考官方:
ARouter
2.源码解析:
1.ARouter初始化过程:
Application初始化时要初始化ARouter:
public class MyApplication extends Application {
public void onCreate() {
...
ARouter.init(MyApplication.this);
}
}
ARouter初始化的过程:
public final class ARouter {
private volatile static _ARouter instance = null;
private static Handler mHandler;
private volatile static boolean hasInit = false;
protected static _ARouter getInstance() {
...
return instance;
}
public static void init(Application application) {
if (!hasInit) {
mContext = application;
LogisticsCenter.init(mContext, executor);
hasInit = true;
mHandler = new Handler(Looper.getMainLooper());
}
}
}
LogisticsCenter初始化:
//className = LogisticsCenter
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
Set<String> routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
for (String className : routerMap) {
//className以com.alibaba.android.arouter.routes.ARouter$$Root开头
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
//这里只会把一级目录(也就是Group)放入Warehouse的组路由表中
((IRouteRoot) (Class.forName(className).getConstructor()
.newInstance())).loadInto(Warehouse.groupsIndex);
}
//className以com.alibaba.android.arouter.routes.ARouter$$Interceptors开头
else if(className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
((IInterceptorGroup) (Class.forName(className).getConstructor()
.newInstance())).loadInto(Warehouse.interceptorsIndex);
}
//className以com.alibaba.android.arouter.routes.ARouter$$Providers开头
else if(className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
((IProviderGroup) (Class.forName(className).getConstructor()
.newInstance())).loadInto(Warehouse.providersIndex);
}
}
}
ClassUtils类获取全部路由类的过程,这里开启了新的线程扫描整个APK中所有的类,找到特定的类名返回;
//扫描所有APK,把包名为packageName的所有类的类名添加到Set并返回
public static Set<String> getFileNameByPackageName(Application context, final String packageName)
throws PackageManager.NameNotFoundException, InterruptedException {
final Set<String> classNames = new HashSet<>();
//获得所有APK的路径
List<String> paths = getSourcePaths(context);
//使用同步计数器判断均处理完成
final CountDownLatch countDownLatch = new CountDownLatch(paths.size());
ThreadPoolExecutor threadPoolExecutor = DefaultPoolExecutor.newDefaultPoolExecutor(paths.size());
for (final String path : paths) { //遍历每个APK
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
DexFile dexFile = null;
try {
//加载 apk中的dex 并遍历 获得所有包名为 {packageName} 的类
dexFile = new DexFile(path);
Enumeration<String> dexEntries = dexFile.entries();
while (dexEntries.hasMoreElements()) {
String className = dexEntries.nextElement();
//找到前缀为特定字符串的类名,因为APT生成的类都会以这个前缀命名,
//所以这里找到的是所有处理Router注解的APT生成的类的全名
if (!TextUtils.isEmpty(className) && className.startsWith(packageName)) {
classNames.add(className);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
}
});
}
//等待执行完成
countDownLatch.await();
return classNames;
}
定义路由添加路由的接口:
public interface IRouteGroup {
void loadInto(Map<String, RouteMeta> atlas);
}
public interface IRouteRoot {
void loadInto(Map<String, Class<? extends IRouteGroup>> routes);
}
用APT在编译期间生成Java类,用来将被Router注解标记的类添加到路由表中:
@AutoService(Processor.class)
@SupportedOptions({KEY_MODULE_NAME, KEY_GENERATE_DOC_NAME})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})
public class RouteProcessor extends AbstractProcessor {
private Map<String, Set<RouteMeta>> groupMap = new HashMap<>(); // ModuleName and routeMeta.
private Map<String, String> rootMap = new TreeMap<>(); // Map of root metas, used for generate class file
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (!Utils.isEmpty(set)) {
//被Route注解的节点集合
Set<? extends Element> rootElements = roundEnvironment.getElementsAnnotatedWith(Route.class);
if (!Utils.isEmpty(rootElements)) {
//遍历rootElements,生成java文件,略;
processorRoute(rootElements);
}
return true;
}
return false;
}
}
生成的java文件形如:
//把某个分组放入路由表中
public class ARouter_Root_app implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("main", EaseRouter_Group_main.class);
routes.put("show", EaseRouter_Group_show.class);
}
}
//把某个分组下的类放如路由表中
public class ARouter_Group_main implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/main/main",RouteMeta.build(RouteMeta.Type.ACTIVITY,Main2\Activity.class,"/main/main","main"));
atlas.put("/main/main2",RouteMeta.build(RouteMeta.Type.ACTIVITY,Main2\Activity.class,"/main/main2","main"));
}
}
管理路由表的类Warehouse
class Warehouse {
// Cache route and metas
//初始化完成之后或填充这个Map
static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
static Map<String, RouteMeta> routes = new HashMap<>();
// Cache provider
static Map<Class, IProvider> providers = new HashMap<>();
static Map<String, RouteMeta> providersIndex = new HashMap<>();
// Cache interceptor
static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
static List<IInterceptor> interceptors = new ArrayList<>();
static void clear() {
routes.clear();
groupsIndex.clear();
providers.clear();
providersIndex.clear();
interceptors.clear();
interceptorsIndex.clear();
}
}
总结:
ARouter初始化会全局搜索@Route注解,这些带有@Router注解的类会通过APT生成Java文件,初始化的过程中会创建这些类的实例,执行这些类的方法就会填充Warehouse中的路由表
2.页面跳转的过程:
ARouter.getsInstance().build("/module1/module1main").navigation();
这里build方法返回的是一个PostCard对象,PostCard又是RouteMeta的子类:
public class RouteMeta {
private RouteType type; //当前路径对应的类型,如Activity
private Element rawType;
private Class<?> destination; //用destination就可以创建想要的类
private String path;
private String group;
private int priority = -1;
private int extra;
private Map<String, Integer> paramsType;
private String name;
private Map<String, Autowired> injectConfig;
}
public class Postcard extends RouteMeta {
private Bundle mBundle;
private int flags = -1;
private Bundle optionsCompat;
private int enterAnim;
private int exitAnim;
protected Object navigation(Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
//准备Postcard中的参数
prepareCard(postcard);
switch (postcard.getType()) {
case ACTIVITY:
//根据PostCard中的参数构建Intent,并启动Activity
final Context currentContext = null == context ? mContext : context;
final Intent intent = new Intent(currentContext, postcard.getDestination());
intent.putExtras(postcard.getExtras());
mHandler.post(new Runnable() {
@Override
public void run() {
//可能需要返回码
if (requestCode > 0) {
ActivityCompat.startActivityForResult((Activity) currentContext, intent,
requestCode, postcard.getOptionsBundle());
} else {
ActivityCompat.startActivity(currentContext, intent, postcard
.getOptionsBundle());
}
//跳转完成
if (null != callback) {
callback.onArrival(postcard);
}
}
});
break;
default:
break;
}
return null;
}
//这个方法就是把Warehouse中某路径对应的RouteMeta的关键信息赋值给Postcard
private void prepareCard(Postcard card) {
//从路由表中获取Activity类信息
RouteMeta routeMeta = Warehouse.routes.get(card.getPath());
//初始化时为了节省性能,只会加载所有的分组信息,而每个分组下的路由映射关系,会使用懒加载,在首次用到的时候去加载
if (null == routeMeta) {
//获取url对应的Group
Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(card.getGroup());
IRouteGroup iGroupInstance;
//创建一个IRouteGroup对象
iGroupInstance = groupMeta.getConstructor().newInstance();
iGroupInstance.loadInto(Warehouse.routes);
Warehouse.groupsIndex.remove(card.getGroup());
//再次执行会进入else分支
prepareCard(card);
} else {
//将RouteMeta里面保存的activityClass放入Postcard里面
card.setDestination(routeMeta.getDestination());
card.setType(routeMeta.getType());
switch (routeMeta.getType()) {
case ISERVICE:
Class<?> destination = routeMeta.getDestination();
IService service = Warehouse.services.get(destination);
if (null == service) {
try {
service = (IService) destination.getConstructor().newInstance();
Warehouse.services.put(destination, service);
} catch (Exception e) {
e.printStackTrace();
}
}
card.setService(service);
break;
default:
break;
}
}
}
}
总结:
跳转的过程就是根据Url查询路由表,用路由表中的信息初始化一个构造一个PostCard,然后通过PostCard构造一个Intent开启Activity