ARouter源码探究
ARouter源碼探究
1. 疑問
源碼是最好的老師,我們帶著這些疑問去源碼中尋找答案;
其實ARouter有上述功能我總結有二個關鍵點:APT、反射
下面我們從編譯期,ARouter初始化,route三個方面進行分析
2. 編譯期間做了什么?
https://github.com/alibaba/ARouter.git我們以官方源碼為例進行剖析,下載源碼后終端輸入如下命令
cd ARouter && ./gradlew clean assembleDebug構建成功后你看到的目錄結構如下
App:主工程
arouter-annotation:存放ARouter注解的Module
arouter-compiler:編譯期間動態生成代碼的邏輯
arouter-api: ARouter大部分的內部實現設計
arouter-register:支持第三方加固
module-java:跨模塊調用演示
module-kotlin:支持Kotlin
我們先熟悉下幾個類
Route注解
可以看到Route注解中的path就是跳轉的路由,group是其對應的分組(按需加載用到);需要說明的是ARouter除了支持跳轉Activity外還支持其他類型
Arouter的跳轉類型
從上面可推測目前應該支持挑轉Activity,Service,ContentProvider以及Java接口
APT(注解處理器)
APT(Annotation Processing Tool)即注解處理器,是一種處理注解的工具,確切的說它是javac的一個工具,它用來在編譯時掃描和處理注解。注解處理器以Java代碼(或者編譯過的字節碼)作為輸入,生成.java文件作為輸出。簡單來說就是在編譯期,通過注解生成.java文件。用過Dagger、EventBus等注解框架同學都能感受到,使用這些框架只要寫一些注解就可以了,使用起來非常方便;其實它們都是通過讀取注解,生成了一些代碼而已;
Arouter的參數的自動注入,支持攔截,path和類如何建立映射,都是和注解處理器分不開的;
我們來看app工程中自動生成的代碼有哪些
我挑選分組為test、service代碼來看看,可以看到下面二個類名的末尾都是使用自身的組名來拼接而成的;因為ARouter是運行期間按組加載路由而不是一次性載入,而下面的二個類也正是基于這一考慮而生成的;每個類只負責加載自己組內路由,一個類只做一件事情
既然ARouter要做到按組加載路由,那肯定有一個存放所有分組映射的類,以便于快速定位分組類,我們發現有個Arouter$$Root$app類,它就是我們猜想的那個類,key存放組名,value存放其對應的映射類
攔截器生成類:
可以看到該類中包含了聲明的所有攔截器類,key對應就是其優先級
我們用一張圖概括編譯期間做了啥
從上圖看出編譯器做了二件事情
3. 初始化做了什么?
一張圖總結如下:
下面我們具體分析下
//ARouter.java /*** Init, it must be call before used router.*/ public static void init(Application application) {if (!hasInit) {logger = _ARouter.logger;_ARouter.logger.info(Consts.TAG, "ARouter init start.");hasInit = _ARouter.init(application);if (hasInit) {_ARouter.afterInit();}_ARouter.logger.info(Consts.TAG, "ARouter init over.");} }//_ARouter.java protected static synchronized boolean init(Application application) {mContext = application;LogisticsCenter.init(mContext, executor);logger.info(Consts.TAG, "ARouter init success!");hasInit = true;// It's not a good idea.// if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {// application.registerActivityLifecycleCallbacks(new AutowiredLifecycleCallback());// }return true;}我們看到Arouter的初始化其實最后還是由LogisticsCenter這個類來做的
我們直接從第一個else語句后面看源代碼如下
//LogisticsCenter.java//public static final String ROUTE_ROOT_PAKCAGE = "com.alibaba.android.arouter.routes"; //public static final String DOT = "."; //public static final String SDK_NAME = "ARouter";if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {logger.info(TAG, "Run with debug mode or new install, rebuild router map.");// These class was generated by arouter-compiler.//1、讀取com.alibaba.android.arouter.routes包名下所有類routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);if (!routerMap.isEmpty()) {//2、把指定包名下的類都保存到本地了,便于下次直接從文件讀取context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();}// Save new version name when router map update finishes.PackageUtils.updateVersion(context); } else {logger.info(TAG, "Load router map from cache.");//3、從sp中直接讀取類信息routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>())); }logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms."); startInit = System.currentTimeMillis();//4、將指定前綴的包名的類加載到內存中(Warehouse) for (String className : routerMap) {if (className.startsWith("com.alibaba.android.arouter.routes.ARouter$$Root")) {// This one of root elements, load root.((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);} else if (className.startsWith("com.alibaba.android.arouter.routes.ARouter$$Interceptors")) {// Load interceptorMeta((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);} else if (className.startsWith("com.alibaba.android.arouter.routes.ARouter$$Providers")) {// Load providerIndex((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);} }小結上面代碼,主要做了二件事情,
尋找指定包名的所有類
通過線程池讀取所有dex中指定包名類,此處也就解釋了為什么ARouter支持InstantRun、MultiDex
通過反射創建對象,并加載到內存(Warehouse)
可以看到初始化過程其實加載到Warehouse類中有groupsIndex、interceptorsIndex、providersIndex
4. 路由做了什么 ?
ARouter跳轉一般是這樣
ARouter.getInstance().build("/test/activity").navigation(this, new NavCallback() {@Overridepublic void onArrival(Postcard postcard) {}@Overridepublic void onInterrupt(Postcard postcard) {Log.d("ARouter", "被攔截了");}});跟蹤代碼可以發現ARouter.build最后還是委托給_Arouter.build來做,navigation也是同理
//_ARouter.java /** * Build postcard by path and default group */ protected Postcard build(String path) {if (TextUtils.isEmpty(path)) {throw new HandlerException(Consts.TAG + "Parameter is invalid!");} else {PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);if (null != pService) {path = pService.forString(path);}return build(path, extractGroup(path));} }/*** Build postcard by uri*/ protected Postcard build(Uri uri) {if (null == uri || TextUtils.isEmpty(uri.toString())) {throw new HandlerException(Consts.TAG + "Parameter invalid!");} else {PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);if (null != pService) {uri = pService.forUri(uri);}return new Postcard(uri.getPath(), extractGroup(uri.getPath()), uri, null);} }最終返回了一個Postcard對象,可以將其理解為route過程中攜帶的數據包,該數據包括了path、group、參數,目標類等等
我們接下來重點看_ARouter.navigation內部怎么做的
protected Object navigation(final Context context,final Postcard postcard, final int requestCode, final NavigationCallback callback) {try {//1、豐富postcard數據LogisticsCenter.completion(postcard);} catch (NoRouteFoundException ex) {//2、異常處理logger.warning(Consts.TAG, ex.getMessage());if (debuggable()) { // Show friendly tips for user.Toast.makeText(mContext, "There's no route matched!\n" +" Path = [" + postcard.getPath() + "]\n" +" Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();}if (null != callback) {callback.onLost(postcard);} else { // No callback for this invoke, then we use the global degrade service.DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);if (null != degradeService) {degradeService.onLost(context, postcard);}}//直接返回了哦return null;}//3、回調事件處理if (null != callback) {callback.onFound(postcard);}// It must be run in async thread, maybe interceptor cost too mush time made ANR.if (!postcard.isGreenChannel()) { //4、非綠色通道先過攔截器interceptorService.doInterceptions(postcard, new InterceptorCallback() {/*** Continue process** @param postcard route meta*/@Overridepublic void onContinue(Postcard postcard) {//5、真正跳轉邏輯_navigation(context, postcard, requestCode, callback);}/*** Interrupt process, pipeline will be destory when this method called.** @param exception Reson of interrupt.*/@Overridepublic void onInterrupt(Throwable exception) {if (null != callback) {callback.onInterrupt(postcard);}logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());}});} else {return _navigation(context, postcard, requestCode, callback);}return null;}總結下其實流程還是很清晰的
豐富postcard
你要知道跳轉的目標類,首先你就得從根索引類中找,提取出注解相關的數據,并設置給postcard;這些都是LogisticsCenter.completion(postcard)干的活
異常處理
當你的path沒找到,調用callback.onLost后直接返回了
回調事件處理
path找到了則直接調用callback.onFound
分發到攔截器
當路由請求為非綠色通道都是先過攔截器,攔截器歸還控制權后繼續執行第五流程
最后跳轉流程
包含Activity跳轉,Fragment、Provider實例的生成
附上navigation主流程圖
下面我們繼續對1、4、5子流程進行深入追蹤
4.1 豐富postcard
//LogisticsCenter.java public synchronized static void completion(Postcard postcard) {if (null == postcard) {throw new NoRouteFoundException(TAG + "No postcard!");}//從路由緩存中查找改path是否有路由記錄RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());// Maybe its does't exist, or didn't load.if (null == routeMeta) { //如果routes不存在,嘗試從根索引類入口尋找(明白了ARouter如何實現動態分組加載機制了吧?)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() + "]");}//此處調用自身方法,其實是執行了下面的else語句代碼completion(postcard); // Reload}} else {//豐富postcard對象數據(來源于注解的解析)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//此處是通過url中的參數數據(eg:xxx/xxx?a=1&b=abc)并結合目標類中注解攜帶的信息//來確定每個參數的數據類型,進而設置到bundle中for (Map.Entry<String, Integer> params : paramsType.entrySet()) {setValue(postcard,params.getValue(),params.getKey(),resultMap.get(params.getKey()));}// Save params name which need auto inject.postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));}// Save raw uripostcard.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 implement IProviderClass<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();IProvider instance = Warehouse.providers.get(providerMeta);if (null == instance) { // There's no instance of this providerIProvider 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 interceptorsbreak;case FRAGMENT:postcard.greenChannel(); // Fragment needn't interceptorsdefault:break;}} }所以我們知道completion方法目標就是很簡單,就是給postcard設置諸多參數,為后面跳轉做服務
4.2 分發到攔截器
從上面代碼我們知道路由事件分發給攔截器是通過interceptorService.doInterceptions來實現的,那么interceptorService對象是什么時候被創建?跟蹤代碼發現是afterInit方法觸發的,而afterInit只在ARouter初始化被調用
//_ARouter.java static void afterInit() {// Trigger interceptor init, use byName.interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation(); }//ARouter.java /*** Init, it must be call before used router.*/ public static void init(Application application) {if (!hasInit) {logger = _ARouter.logger;_ARouter.logger.info(Consts.TAG, "ARouter init start.");hasInit = _ARouter.init(application);if (hasInit) {_ARouter.afterInit();}_ARouter.logger.info(Consts.TAG, "ARouter init over.");} }現在我們明白了攔截器服務初始化時機,接下來看看攔截器服務實現類InterceptorServiceImpl
攔截器服務初始化時加載所有自定義攔截器,這樣便于doInterceptions方法正常進行
@Route(path = "/arouter/service/interceptor") public class InterceptorServiceImpl implements InterceptorService {private static boolean interceptorHasInit;private static final Object interceptorInitLock = new Object();//使用線程池(考慮到反射耗時)來加載所有攔截器@Overridepublic void init(final Context context) {LogisticsCenter.executor.execute(new Runnable() {@Overridepublic void run() {//interceptorsIndex類型是UniqueKeyTreeMap//這也解釋了為什么能夠自定義攔截器優先級了if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {Class<? extends IInterceptor> interceptorClass = entry.getValue();try {IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();iInterceptor.init(context);//創建的所有攔截器放到數組中Warehouse.interceptors.add(iInterceptor);} catch (Exception ex) {throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName()+ "], reason = [" + ex.getMessage()+ "]");}}interceptorHasInit = true;logger.info(TAG, "ARouter interceptors init over.");synchronized (interceptorInitLock) {//喚醒其他等待的線程interceptorInitLock.notifyAll();}}}});}private static void checkInterceptorsInitStatus() {synchronized (interceptorInitLock) {while (!interceptorHasInit) {try {interceptorInitLock.wait(10 * 1000);} catch (InterruptedException e) {throw new HandlerException(TAG + "Interceptor init cost too much time error! reason = [" + e.getMessage() + "]");}}}}@Overridepublic void doInterceptions(final Postcard postcard,final InterceptorCallback callback) {if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {//1、判斷攔截器服務是否初始化完成,沒完成等它10s再說checkInterceptorsInitStatus();if (!interceptorHasInit) {//2、10s還沒搞定,直接回掉并返回callback.onInterrupt(new HandlerException("Interceptors"+"initialization takes too much time."));return;}LogisticsCenter.executor.execute(new Runnable() {@Overridepublic void run() {//3、使用CountDownLatch是為了在多線程中做到攔截器順序執行//使用線程池則是為了提高資源利用率CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());try {//4、按順序(優先級)執行所有攔截器_excute(0, interceptorCounter, postcard);//在指定時間內等待_excute方法執行完成interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);//5、主要是回掉事件的處理了// Cancel the navigation this time, if it hasn't return anythings.if (interceptorCounter.getCount() > 0) { callback.onInterrupt(new HandlerException("The interceptor"+"processing timed out."));} else if (null != postcard.getTag()) { // Maybe some exception in the tag.callback.onInterrupt(new HandlerException(postcard.getTag().toString()));} else {callback.onContinue(postcard);}} catch (Exception e) {callback.onInterrupt(e);}}});} else {//無攔截器則執行_navigation也就是下面要說的跳轉流程,callback.onContinue(postcard);}} }小結下,攔截器服務主要做了一下幾個時期
4.3 最后跳轉
//_ARouter.java 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://1、設置相關參數// Build intentfinal 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);}//2、UI線程啟動Activity// Navigation in main looper.new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() {if (requestCode > 0) { // Need start for resultActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());} else {ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());}//3、收尾操作包括動畫及其回調處理if ((-1 != postcard.getEnterAnim() && -1 != 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://從這里我們可以看到ARouter是通過反射方式創建fragmentClass 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()));}case METHOD:case SERVICE:default:return null;}return null; }從上面我們可以看到目前ARouter只能支持Activity、Fragment、Provider三種方式;啟動服務,ContentProvider目前還不支持;前面的豐富postcard操作就是為最后一步做鋪墊的。
至此ARouter的route流程大體已講解完畢;
5. 如何實現頁面自動注入參數?
接下來我們來看下ARouter是如何自動注入參數的,以Activity為例
//Router 跳轉 TestObj testObj = new TestObj("Rose", 777);ARouter.getInstance().build("/test/activity1").withString("name", "老王").withInt("age", 18).withBoolean("boy", true).withObject("obj", testObj).navigation();//參數自動注入 // 為每一個參數聲明一個字段,并使用 @Autowired 標注 // URL中不能傳遞Parcelable類型數據,通過ARouter api可以傳遞Parcelable對象 @Route(path = "/test/activity") public class Test1Activity extends Activity {@Autowiredpublic String name;@Autowiredint age;@Autowired(name = "girl") // 通過name來映射URL中的不同參數boolean boy;@AutowiredTestObj obj; // 支持解析自定義對象,URL中使用json傳遞,需要序列化和反序列化服務接口支持@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ARouter.getInstance().inject(this);// ARouter會自動對字段進行賦值,無需主動獲取Log.d("param", name + age + boy);} }// 如果需要傳遞自定義對象,需要實現 SerializationService,并使用@Route注解標注(方便用戶自行選擇序列化方式),例如: @Route(path = "/service/json") public class JsonServiceImpl implements SerializationService {@Overridepublic void init(Context context) {}@Overridepublic <T> T json2Object(String text, Class<T> clazz) {return JSON.parseObject(text, clazz);}@Overridepublic String object2Json(Object instance) {return JSON.toJSONString(instance);} }我們自然想到參數自動注入就是ARouter.getInstance().inject(this);搞的鬼,進去看看
//ARouter.java /*** Inject params and services.*/ public void inject(Object thiz) {_ARouter.inject(thiz); }//_ARouter.java static void inject(Object thiz) {AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());if (null != autowiredService) {autowiredService.autowire(thiz);}}從上面可以看到ARouter.inject要做的事情委托給了_ARouter.inject;而__ARouter不愿干直接扔給一個叫AutowiredService類處理了;我們找找其實現類AutowiredServiceImpl它才是實現參數自動注入的關鍵代碼
@Route(path = "/arouter/service/autowired") public class AutowiredServiceImpl implements AutowiredService {private LruCache<String, ISyringe> classCache;private List<String> blackList;@Overridepublic void init(Context context) {classCache = new LruCache<>(66);blackList = new ArrayList<>();}@Overridepublic void autowire(Object instance) {String className = instance.getClass().getName();try {if (!blackList.contains(className)) {//1、從緩存查到代理類ISyringe autowiredHelper = classCache.get(className);if (null == autowiredHelper) { // No cache.//沒找到,則嘗試創建一個對象,該對象名字規則如下//eg:xxxx.Test1Activity$$ARouter$$AutowiredautowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();}//2、交給代理類去做了autowiredHelper.inject(instance);//3、緩存起來classCache.put(className, autowiredHelper);}} catch (Exception ex) {blackList.add(className); // This instance need not autowired.}} }所以說_ARouter、AutowiredServiceImpl的inject都不想干活最后還是Test1Activity$$ARouter$$Autowired類老老實實做,下圖就是參數自動注入的代碼了,代碼很簡單就不廢話了;可以看到自定義對象是使用了一個叫serralizationService的反序列化服務來完成的;
至于Test1Activity$$ARouter$$Autowired類是如何生成的,有興趣的同學可以看AutowiredProcessor類的內部實現;可能有同學有疑問,自定義對象數據是如何做到反序列化的?不知道大家有沒注意在豐富postcard流程是有一句setValue代碼,進去看看
private static void setValue(Postcard postcard, Integer typeDef, String key, String value) {if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {return;}try {if (null != typeDef) {if (typeDef == TypeKind.BOOLEAN.ordinal()) {postcard.withBoolean(key, Boolean.parseBoolean(value));} else if (typeDef == TypeKind.BYTE.ordinal()) {postcard.withByte(key, Byte.valueOf(value));} else if (typeDef == TypeKind.SHORT.ordinal()) {postcard.withShort(key, Short.valueOf(value));} else if (typeDef == TypeKind.INT.ordinal()) {postcard.withInt(key, Integer.valueOf(value));} else if (typeDef == TypeKind.LONG.ordinal()) {postcard.withLong(key, Long.valueOf(value));} else if (typeDef == TypeKind.FLOAT.ordinal()) {postcard.withFloat(key, Float.valueOf(value));} else if (typeDef == TypeKind.DOUBLE.ordinal()) {postcard.withDouble(key, Double.valueOf(value));} else if (typeDef == TypeKind.STRING.ordinal()) {postcard.withString(key, value);} else if (typeDef == TypeKind.PARCELABLE.ordinal()) {// TODO : How to description parcelable value with string?} else if (typeDef == TypeKind.OBJECT.ordinal()) {//解釋了自定義對象為什么能實現序列化原因了postcard.withString(key, value);} else { // Compatible compiler sdk 1.0.3, in that version, the string type = 18postcard.withString(key, value);}} else {postcard.withString(key, value);}} catch (Throwable ex) {logger.warning(Consts.TAG, "LogisticsCenter setValue failed! " + ex.getMessage());} }所以自定義對象數據其原始還是字符串承載,等到目標頁面時再通過反序列化服務處理就OK了,同時也清楚為什么對于自定義對象參數時需要實現序列化服務了
至此ARouter的流程已基本梳理完畢!
總結
以上是生活随笔為你收集整理的ARouter源码探究的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android-Multidex安装流程
- 下一篇: Mac 系统如何实现挂载NTFS文件系统