首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ARouter 传自定义对象获取值为null的解析 及解决方法

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

作者头像
Xiaolei123
修改2022-06-19 14:05:41
3.2K0
修改2022-06-19 14:05:41
举报
文章被收录于专栏:肖蕾的博客肖蕾的博客

首先

我在使用 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 找到关键点

private String buildStatement(String originalValue, String statement, int type, boolean isActivity) {
        if (type == TypeKind.BOOLEAN.ordinal()) {
            statement += (isActivity ? ("getBooleanExtra($S, " + originalValue + ")") : ("getBoolean($S)"));
        } else if (type == TypeKind.BYTE.ordinal()) {
            statement += (isActivity ? ("getByteExtra($S, " + originalValue + ")") : ("getByte($S)"));
        } else if (type == TypeKind.SHORT.ordinal()) {
            statement += (isActivity ? ("getShortExtra($S, " + originalValue + ")") : ("getShort($S)"));
        } else if (type == TypeKind.INT.ordinal()) {
            statement += (isActivity ? ("getIntExtra($S, " + originalValue + ")") : ("getInt($S)"));
        } else if (type == TypeKind.LONG.ordinal()) {
            statement += (isActivity ? ("getLongExtra($S, " + originalValue + ")") : ("getLong($S)"));
        }else if(type == TypeKind.CHAR.ordinal()){
            statement += (isActivity ? ("getCharExtra($S, " + originalValue + ")") : ("getChar($S)"));
        } else if (type == TypeKind.FLOAT.ordinal()) {
            statement += (isActivity ? ("getFloatExtra($S, " + originalValue + ")") : ("getFloat($S)"));
        } else if (type == TypeKind.DOUBLE.ordinal()) {
            statement += (isActivity ? ("getDoubleExtra($S, " + originalValue + ")") : ("getDouble($S)"));
        } else if (type == TypeKind.STRING.ordinal()) {
            statement += (isActivity ? ("getStringExtra($S)") : ("getString($S)"));
        } else if (type == TypeKind.SERIALIZABLE.ordinal()) {
            statement += (isActivity ? ("getSerializableExtra($S)") : ("getSerializable($S)"));
        } else if (type == TypeKind.PARCELABLE.ordinal()) {
            statement += (isActivity ? ("getParcelableExtra($S)") : ("getParcelable($S)"));
        } else if (type == TypeKind.OBJECT.ordinal()) {
            statement = "serializationService.parseObject(substitute." + (isActivity ? "getIntent()." : "getArguments().") + (isActivity ? "getStringExtra($S)" : "getString($S)") + ", new com.alibaba.android.arouter.facade.model.TypeWrapper<$T>(){}.getType())";
        }

        return statement;
    }

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

追踪 TypeKind

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

public enum TypeKind {
    // Base type
    BOOLEAN,
    BYTE,
    SHORT,
    INT,
    LONG,
    CHAR,
    FLOAT,
    DOUBLE,

    // Other type
    STRING,
    SERIALIZABLE,
    PARCELABLE,
    OBJECT;
}

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

image

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

追踪 TypeUtils

关键部分代码:

/**
 * Diagnostics out the true java type
 *
 * @param element Raw type
 * @return Type class of java
 */
public int typeExchange(Element element) {
    TypeMirror typeMirror = element.asType();

    // Primitive
    if (typeMirror.getKind().isPrimitive()) {
        return element.asType().getKind().ordinal();
    }

    switch (typeMirror.toString()) {
        case BYTE:
            return TypeKind.BYTE.ordinal();
        case SHORT:
            return TypeKind.SHORT.ordinal();
        case INTEGER:
            return TypeKind.INT.ordinal();
        case LONG:
            return TypeKind.LONG.ordinal();
        case FLOAT:
            return TypeKind.FLOAT.ordinal();
        case DOUBEL:
            return TypeKind.DOUBLE.ordinal();
        case BOOLEAN:
            return TypeKind.BOOLEAN.ordinal();
        case CHAR:
            return TypeKind.CHAR.ordinal();
        case STRING:
            return TypeKind.STRING.ordinal();
        default:    // Other side, maybe the PARCELABLE or SERIALIZABLE or OBJECT.
            if (types.isSubtype(typeMirror, parcelableType)) {  // PARCELABLE
                return TypeKind.PARCELABLE.ordinal();
            } else if (types.isSubtype(typeMirror, serializableType)) {  // PARCELABLE
                return TypeKind.SERIALIZABLE.ordinal();
            } else {    // For others
                return TypeKind.OBJECT.ordinal();
            }
    }
}

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

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

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

老群被封,+新Q群709287944

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.01.11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 首先
  • 使用 withObject传值
  • 取值
  • 再跟踪
  • 问题排查,以及解决方案
  • 追踪 TypeKind
  • 追踪 TypeUtils
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档