组件化框架设计之阿里巴巴开源路由框架——ARouter原理分析(一)

总结

可以看出,笔者的工作学习模式便是由以下 「六个要点」 组成:

❝ 多层次的工作/学习计划 + 番茄工作法 + 定额工作法 + 批处理 + 多任务并行 + 图层工作法❞

希望大家能将这些要点融入自己的工作学习当中,我相信一定会工作与学习地更富有成效。

下面是我学习用到的一些书籍学习导图,以及系统的学习资料。每一个知识点,都有对应的导图,学习的资料,视频,面试题目。

**如:我需要学习 **Flutter的知识。(大家可以参考我的学习方法)

  • Flutter 的思维导图(无论学习什么,有学习路线都会事半功倍)

  • Flutter进阶学习全套手册

  • Flutter进阶学习全套视频

大概就上面这几个步骤,这样学习不仅高效,而且能系统的学习新的知识。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

List classFileNames = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);

//

for (String className : classFileNames) {

if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {

// This one of root elements, load root.

((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);

} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {

// Load interceptorMeta

((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);

} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {

// Load providerIndex

((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);

}

}

我们可以看到,首先是去获取到所有的app里的由ARouter注解生成的类的类名,他们的统一特点就是在同一个包下,包名为:com.alibaba.android.arouter.routes

然后就是循环遍历这些类,也就是刚才我们说的那三种类。在这里,有一个Warehouse类,看下代码:

/**

  • Storage of route meta and other data.

  • @author zhilong Contact me.

  • @version 1.0

  • @since 2017/2/23 下午1:39

*/

class Warehouse {

// Cache route and metas

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 interceptors = new ArrayList<>();

static void clear() {

routes.clear();

groupsIndex.clear();

providers.clear();

providersIndex.clear();

interceptors.clear();

interceptorsIndex.clear();

}

}

很简单,定义了几个静态map,在初始化的时候来存放之前的注解生成的那些相关信息。初始化里面存的就是所有group索引的map,所有拦截器(本文不讲)索引的map,所有provider索引的map。至此,之前的那些注解类里面的信息都被存储起来了,这样后续在查找的时候就很方便可以找到对应的类,我们继续看初始化之后的afterInit方法:

static void afterInit() {

// Trigger interceptor init, use byName.

interceptorService = (InterceptorService) ARouter.getInstance().build(“/arouter/service/interceptor”).navigation();

}

我们跟踪之后,发现最终会调用LogisticsCenter中的completion方法:

/**

  • Completion the postcard by route metas

  • @param postcard Incomplete postcard, should completion by this method.

*/

public synchronized static void completion(Postcard postcard) {

if (null == postcard) {

throw new NoRouteFoundException(TAG + “No postcard!”);

}

RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());

if (null == routeMeta) { // Maybe its does’t exist, or didn’t load.

Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); // Load route meta.

if (null == groupMeta) {

throw new NoRouteFoundException(TAG + “There is no route match the path [” + postcard.getPath() + “], in group [” + postcard.getGroup() + “]”);

} else {

// Load route and cache it into memory, then delete from metas.

try {

if (ARouter.debuggable()) {

logger.debug(TAG, String.format(Locale.getDefault(), “The group [%s] starts loading, trigger by [%s]”, postcard.getGroup(), postcard.getPath()));

}

IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();

iGroupInstance.loadInto(Warehouse.routes);

Warehouse.groupsIndex.remove(postcard.getGroup());

if (ARouter.debuggable()) {

logger.debug(TAG, String.format(Locale.getDefault(), “The group [%s] has already been loaded, trigger by [%s]”, postcard.getGroup(), postcard.getPath()));

}

} catch (Exception e) {

throw new HandlerException(TAG + “Fatal exception when loading group meta. [” + e.getMessage() + “]”);

}

completion(postcard); // Reload

}

} else {

postcard.setDestination(routeMeta.getDestination());

postcard.setType(routeMeta.getType());

postcard.setPriority(routeMeta.getPriority());

postcard.setExtra(routeMeta.getExtra());

Uri rawUri = postcard.getUri();

if (null != rawUri) { // Try to set params into bundle.

Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);

Map<String, Integer> paramsType = routeMeta.getParamsType();

if (MapUtils.isNotEmpty(paramsType)) {

// Set value by its type, just for params which annotation by @Param

for (Map.Entry<String, Integer> params : paramsType.entrySet()) {

setValue(postcard,

params.getValue(),

params.getKey(),

resultMap.get(params.getKey()));

}

// Save params name which need autoinject.

postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));

}

// Save raw uri

postcard.withString(ARouter.RAW_URI, rawUri.toString());

}

switch (routeMeta.getType()) {

case PROVIDER: // if the route is provider, should find its instance

// Its provider, so it must be implememt IProvider

Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();

IProvider instance = Warehouse.providers.get(providerMeta);

if (null == instance) { // There’s no instance of this provider

IProvider provider;

try {

provider = providerMeta.getConstructor().newInstance();

provider.init(mContext);

Warehouse.providers.put(providerMeta, provider);

instance = provider;

} catch (Exception e) {

throw new HandlerException("Init provider failed! " + e.getMessage());

}

}

postcard.setProvider(instance);

postcard.greenChannel(); // Provider should skip all of interceptors

break;

case FRAGMENT:

postcard.greenChannel(); // Fragment needn’t interceptors

default:

break;

}

}

}

这个方法有点长,不过我们可以看到,核心功能就是postcard的信息完善。postcard就是整个路由过程中的信使,类似于生活中的明信片功能,包含了路由所有需要的信息。通过第34行的递归调用,根据groupsIndex和providersIndex保证了Warehouse里面的另外两个静态map(routes,providers)的赋值,这样最终都会走到36行else分支,去保证所有路由信息的完整性,另外swtich…case里面的postcard.greenChannel()其实是activity跳转专用的,目的是用来拦截activity跳转,来对跳转过程进行干预,在之前或者之后做一些自己的处理,所以greenChannel就是绿色通道,不进行拦截。另外代码里面也可以看到,类的生成都是采用getConstructor().newInstance()这种反射来进行的,最终调用:

ModulePersonalService service = (ModulePersonalService) ARouter.getInstance().build(“/Personal/service”).navigation();

得到这个跨模块服务之后,里面的所有方法都可以去调用来实现功能需求了。

调用过程

Activity的跳转如下:

ARouter.getInstance().build(“/Personal/main”).navigation(activity);

最终调用代码则是_ARouter类里面的_navigation方法:

private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {

final Context currentContext = null == context ? mContext : context;

switch (postcard.getType()) {

case ACTIVITY:

// Build intent

final Intent intent = new Intent(currentContext, postcard.getDestination());

intent.putExtras(postcard.getExtras());

// Set flags.

int flags = postcard.getFlags();

if (-1 != flags) {

intent.setFlags(flags);

} else if (!(currentContext instanceof Activity)) { // Non activity, need less one flag.

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

}

// Navigation in main looper.

new Handler(Looper.getMainLooper()).post(new Runnable() {

@Override

public void run() {

if (requestCode > 0) { // Need start for result

ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());

} else {

ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());

}

if ((0 != postcard.getEnterAnim() || 0 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version.

((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());

}

if (null != callback) { // Navigation over.

callback.onArrival(postcard);

}

}

});

break;

case PROVIDER:

return postcard.getProvider();

case BOARDCAST:

case CONTENT_PROVIDER:

case FRAGMENT:

Class fragmentMeta = postcard.getDestination();

try {

Object instance = fragmentMeta.getConstructor().newInstance();

if (instance instanceof Fragment) {

((Fragment) instance).setArguments(postcard.getExtras());

} else if (instance instanceof android.support.v4.app.Fragment) {

((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());

}

return instance;

} catch (Exception ex) {

logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));

尾声

最后,我再重复一次,如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

容,也知道以后的路怎么走了,理论看多了总要实践的。

进阶学习视频

[外链图片转存中…(img-vltfuXqM-1715469635402)]

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-BCPGTwlD-1715469635403)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值