ARouter 传自定义对象获取值为null的解析 及解决方法

首先

我在使用 withObject 传自定义对象的时候,发现一个BUG,在传值的时候,会走SerializationService的object2Json方法,但是在获取值的时候,竟然不调用parseObject这个方法来转回对象。

我们来一步一步分析

使用 withObject传值

tim 20190111153505

这里可以看到,ARouter 获取了 我们自定义的 SerializationService 并且调用了 object2Json 方法,获取到转换后的字符串,然后将字符串保存到mBundle里

取值

wechat _20190111153939

这里可以看到,ARouter 其实内部根据类名,生成了一个内部类,我们继续跟踪进去

再跟踪

wechat _20190111154119

这里可以看到,其实ARouter已经将我们的自定义的SerializationService 服务实例化,但是不知道怎么回事,却没有将取出来的字符串传进服务里调用 parseObject 这个函数转回对象


OK 以上是问题出现的经过,以及断点逐步分析问题所在,下面说说解决方案

问题排查,以及解决方案

按道理,这么明显的BUG,阿里的工程师不会犯的,所以我把ARouter的代码下载下来之后,导入到AndroidStudio里,首先就去找对应的 AutowiredProcessor 找到关键点

1private String buildStatement(String originalValue, String statement, int type, boolean isActivity) { 2 if (type == TypeKind.BOOLEAN.ordinal()) { 3 statement += (isActivity ? ("getBooleanExtra($S, " + originalValue + ")") : ("getBoolean($S)")); 4 } else if (type == TypeKind.BYTE.ordinal()) { 5 statement += (isActivity ? ("getByteExtra($S, " + originalValue + ")") : ("getByte($S)")); 6 } else if (type == TypeKind.SHORT.ordinal()) { 7 statement += (isActivity ? ("getShortExtra($S, " + originalValue + ")") : ("getShort($S)")); 8 } else if (type == TypeKind.INT.ordinal()) { 9 statement += (isActivity ? ("getIntExtra($S, " + originalValue + ")") : ("getInt($S)")); 10 } else if (type == TypeKind.LONG.ordinal()) { 11 statement += (isActivity ? ("getLongExtra($S, " + originalValue + ")") : ("getLong($S)")); 12 }else if(type == TypeKind.CHAR.ordinal()){ 13 statement += (isActivity ? ("getCharExtra($S, " + originalValue + ")") : ("getChar($S)")); 14 } else if (type == TypeKind.FLOAT.ordinal()) { 15 statement += (isActivity ? ("getFloatExtra($S, " + originalValue + ")") : ("getFloat($S)")); 16 } else if (type == TypeKind.DOUBLE.ordinal()) { 17 statement += (isActivity ? ("getDoubleExtra($S, " + originalValue + ")") : ("getDouble($S)")); 18 } else if (type == TypeKind.STRING.ordinal()) { 19 statement += (isActivity ? ("getStringExtra($S)") : ("getString($S)")); 20 } else if (type == TypeKind.SERIALIZABLE.ordinal()) { 21 statement += (isActivity ? ("getSerializableExtra($S)") : ("getSerializable($S)")); 22 } else if (type == TypeKind.PARCELABLE.ordinal()) { 23 statement += (isActivity ? ("getParcelableExtra($S)") : ("getParcelable($S)")); 24 } else if (type == TypeKind.OBJECT.ordinal()) { 25 statement = "serializationService.parseObject(substitute." + (isActivity ? "getIntent()." : "getArguments().") + (isActivity ? "getStringExtra($S)" : "getString($S)") + ", new com.alibaba.android.arouter.facade.model.TypeWrapper<$T>(){}.getType())"; 26 } 27 28 return statement; 29 }

我们看到最后一行,发现竟然有对 parseObject 这个函数进行调用,但是调用的条件是 type==TypeKind.OBJECT.ordinal()

追踪 TypeKind

那么,这个TypeKind是个什么东西呢?我们找到对应的类:

1public enum TypeKind { 2 // Base type 3 BOOLEAN, 4 BYTE, 5 SHORT, 6 INT, 7 LONG, 8 CHAR, 9 FLOAT, 10 DOUBLE, 11 12 // Other type 13 STRING, 14 SERIALIZABLE, 15 PARCELABLE, 16 OBJECT; 17}

其实就是个枚举,那么这个值是从哪里传过来的呢?

这里可以看到这个函数在这里被调用,传入的值是由 typeUtils 决定的,我们继续追踪

追踪 TypeUtils

关键部分代码:

1/** 2 * Diagnostics out the true java type 3 * 4 * @param element Raw type 5 * @return Type class of java 6 */ 7public int typeExchange(Element element) { 8 TypeMirror typeMirror = element.asType(); 9 10 // Primitive 11 if (typeMirror.getKind().isPrimitive()) { 12 return element.asType().getKind().ordinal(); 13 } 14 15 switch (typeMirror.toString()) { 16 case BYTE: 17 return TypeKind.BYTE.ordinal(); 18 case SHORT: 19 return TypeKind.SHORT.ordinal(); 20 case INTEGER: 21 return TypeKind.INT.ordinal(); 22 case LONG: 23 return TypeKind.LONG.ordinal(); 24 case FLOAT: 25 return TypeKind.FLOAT.ordinal(); 26 case DOUBEL: 27 return TypeKind.DOUBLE.ordinal(); 28 case BOOLEAN: 29 return TypeKind.BOOLEAN.ordinal(); 30 case CHAR: 31 return TypeKind.CHAR.ordinal(); 32 case STRING: 33 return TypeKind.STRING.ordinal(); 34 default: // Other side, maybe the PARCELABLE or SERIALIZABLE or OBJECT. 35 if (types.isSubtype(typeMirror, parcelableType)) { // PARCELABLE 36 return TypeKind.PARCELABLE.ordinal(); 37 } else if (types.isSubtype(typeMirror, serializableType)) { // PARCELABLE 38 return TypeKind.SERIALIZABLE.ordinal(); 39 } else { // For others 40 return TypeKind.OBJECT.ordinal(); 41 } 42 } 43}

原来是在类型判断的时候,如果自定义对象类型是serializable,那么会被当成serializable处理,如果是parcelable那么会被当成parcelable方式处理,只有在不是 parcelable 也不是 serializable 的时候,才会当成自定义对象处理。

所以只需要将自定义的类,不要去实现 Serializable, Parcelable 接口 这两个接口,那么就可以正常传值。

End OK 本次追踪到此结束,有意思。

点赞
收藏

评论区

加载中...

相关推荐

SpringBoot 默认json解析器详解和字段序列化自定义

前言在我们开发项目API接口的时候,一些没有数据的字段会默认返回NULL,数字类型也会是NULL,这个时候前端希望字符串能够统一返回空字符,数字默认返回0,那我们就需要自定义json序列化处理SpringBoot默认的json解析方案我们知道在springboot中有默认的json解析器,SpringBoot中默认使用的Json解析技术框架是ja

FastJson、Jackson、Gson进行Java对象转换Json的细节处理

Java对象转换Json的细节处理前言Java对象在转json的时候,如果对象里面有属性值为null的话,那么在json序列化的时候要不要序列出来呢?对比以下json转换方式一、fastJson1、fastJson在转换java对象为json的时候,默认是不序列化nu

Javascript中的方法链式调用

Javascript中的方法链式调用前言为链式调用创建一个对象为什么报错?解决方法使用闭包实现链式调用前言方法的链式调用这个概念,其实是在面向对象编程中比较常见的语法,它能让使用者在一个对象上连续的调用不同的方法。在不使用临时变量存储中间结果的情

Java多线程带返回值的Callable接口

Java多线程带返回值的Callable接口在面试的时候,有时候是不是会遇到面试会问你,Java中实现多线程的方式有几种?你知道吗?你知道Java中有可以返回值的线程吗?在具体的用法你知道吗?如果两个线程同时来调用同一个计算对象,计算对象的call方法会被调用几次你知道吗?如果这些你知道,那么凯哥(凯哥Java:kaigejava)恭喜你,本文你可以不用

ES6新语法(二)

1.解构在ES6中,可以使用解构从数组和对象提取值并赋值给独特的变量,即将数组或对象中的值,拆成一个一个变量。解构:自动解析数组或对象中的值,并赋值给指定的变量。、1.1数组解构vararr3,4,5;vara,b,carr;

Redis 对象系统

Redis为了更好的实现键值对数据库,创建了一个对象系统,以下为Redis对象系统的相关知识简介。redisObjectRedis使用对象来表示数据库中的键和值,每次在Redis数据库中创建一个键值对时,至少会创建两个对象。一个为键对象,一个为值对象。Redis对象的定义如下:typedef

ARouter 传自定义对象获取值为null的解析 及解决方法 - HelloWorld