美文网首页
Android下谈谈Gson常见优化

Android下谈谈Gson常见优化

作者: 落后程序员 | 来源:发表于2020-06-08 16:35 被阅读0次

在 JSON 中,值必须是以下数据类型之一:
字符串
数字
对象(JSON 对象)
数组
布尔
Null
JSON 的值不可以是以下数据类型之一:
函数
日期
undefined

参考链接:JSON 数据类型

后台返回数据,有的时候受语言限制或者代码没写好的原因,该返回字符串的但是返回null。返回number的但返回字符串,导致客户端序列化对象的时候出现异常

举个栗子,json数据如下:

{
  "tempInt":"",
  "tempString":1111,
  "tempAs":[
    {
      "tempInt":"",
      "tempString":1111
    }
  ],
  "tempA":{
    "tempInt":"",
    "tempString":1111
  }
}

对应的kotlin对象如下

class TestData {
    var tempInt: Int? = 0
    var tempString: String? = ""
    var tempA: A? = null
    var tempAs: List<A>? = null

    class A {
        var tempInt: Int? = 0
        var tempString: String? = ""
        override fun toString(): String {
            return "A(tempInt=$tempInt, tempString=$tempString)"
        }
    }
}

测试代码如下:

    @JvmStatic
    fun main(args: Array<String>) {
        val testData = gson.fromJson(
            "{\n" +
                    "  \"tempInt\":\"\",\n" +
                    "  \"tempString\":1111,\n" +
                    "  \"tempAs\":[\n" +
                    "    {\n" +
                    "      \"tempInt\":\"\",\n" +
                    "      \"tempString\":1111\n" +
                    "    }\n" +
                    "  ],\n" +
                    "  \"tempA\":{\n" +
                    "    \"tempInt\":\"\",\n" +
                    "    \"tempString\":1111\n" +
                    "  }\n" +
                    "}", TestData::class.java
        )
        System.out.println(testData.tempString + "=======" + testData.tempInt)
        System.out.println(testData.tempA?.toString() + "=======" + testData.tempA?.tempInt)
        System.out.println(testData.tempAs.toString())

    }

不处理,就会提示如下报错

Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
    at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:228)
    at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:218)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
    at com.google.gson.Gson.fromJson(Gson.java:927)
    at com.google.gson.Gson.fromJson(Gson.java:892)
    at com.google.gson.Gson.fromJson(Gson.java:841)
    at com.google.gson.Gson.fromJson(Gson.java:813)
    at com.ziqi.baselibrary.util.gson.GsonUtil.main(GsonUtil.kt:42)
Caused by: java.lang.NumberFormatException: empty String
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
    at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
    at java.lang.Double.parseDouble(Double.java:538)
    at com.google.gson.stream.JsonReader.nextInt(JsonReader.java:1201)
    at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:226)
    ... 8 more

但是通过GsonBuilder实现创建gson对象,并使用TypeAdapter来处理每个基本类型,就不会有上面的异常

    val gson: Gson = GsonBuilder() //配置你的Gson
        .registerTypeAdapter(Int::class.java, IntAdapter())
        .registerTypeAdapter(Integer::class.java, IntAdapter())
        .registerTypeAdapter(String::class.java, StringAdapter())
        .registerTypeAdapter(Double::class.java, DoubleAdapter())
        .create()

没有异常并输出内容

1111=======-1
A(tempInt=-1, tempString=1111)=======-1
[A(tempInt=-1, tempString=1111)]

因为一般只会用double,long,int,string这几个基本类型,我就整理封装了一下

DoubleAdapter.kt

package com.ziqi.baselibrary.util.gson

import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException

class DoubleAdapter : TypeAdapter<Double?>() {
    @Throws(IOException::class)
    override fun write(out: JsonWriter?, value: Double?) {
        try {
            var tempValue = value
            if (tempValue == null) {
                tempValue = -1.0
            }
            out?.value(tempValue)
        } catch (e: Exception) {

        }
    }

    @Throws(IOException::class)
    override fun read(`in`: JsonReader): Double? {
        var value: Double? = -1.0
        try {
            if (`in`.peek() == JsonToken.NULL) {
                `in`.nextNull()
                value = -1.0
            } else if (`in`.peek() == JsonToken.BOOLEAN) {
                val b = `in`.nextBoolean()
                value = if (b) 1.0 else 0.0
            } else if (`in`.peek() == JsonToken.STRING) {
                try {
                    value = `in`.nextString().toDouble()
                } catch (e: Exception) {
                    value = -1.0
                }
            } else {
                value = `in`.nextDouble()
            }
        } catch (e: Exception) {
            value = -1.0
        }
        return value
    }
}

IntAdapter.kt

package com.ziqi.baselibrary.util.gson

import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException

class IntAdapter : TypeAdapter<Int?>() {
    @Throws(IOException::class)
    override fun write(out: JsonWriter?, value: Int?) {
        try {
            var tempValue = value
            if (tempValue == null) {
                tempValue = -1
            }
            out?.value(tempValue)
        } catch (e: Exception) {

        }
    }

    @Throws(IOException::class)
    override fun read(`in`: JsonReader): Int? {
        var value: Int? = -1
        try {
            if (`in`.peek() == JsonToken.NULL) {
                `in`.nextNull()
                value = -1
            } else if (`in`.peek() == JsonToken.BOOLEAN) {
                val b = `in`.nextBoolean()
                value = if (b) 1 else 0
            } else if (`in`.peek() == JsonToken.STRING) {
                try {
                    value = `in`.nextString().toInt()
                } catch (e: Exception) {
                    value = -1
                }
            } else {
                value = `in`.nextInt()
            }
        } catch (e: Exception) {
            value = -1
        }
        return value
    }
}

LongAdapter.kt

package com.ziqi.baselibrary.util.gson

import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException

class LongAdapter : TypeAdapter<Long?>() {
    @Throws(IOException::class)
    override fun write(out: JsonWriter?, value: Long?) {
        try {
            var tempValue = value
            if (tempValue == null) {
                tempValue = -1
            }
            out?.value(tempValue)
        } catch (e: Exception) {

        }
    }

    @Throws(IOException::class)
    override fun read(`in`: JsonReader): Long? {
        var value: Long? = -1
        try {
            if (`in`.peek() == JsonToken.NULL) {
                `in`.nextNull()
                value = -1
            } else if (`in`.peek() == JsonToken.BOOLEAN) {
                val b = `in`.nextBoolean()
                value = if (b) 1 else 0
            } else if (`in`.peek() == JsonToken.STRING) {
                try {
                    value = `in`.nextString().toLong()
                } catch (e: Exception) {
                    value = -1
                }
            } else {
                value = `in`.nextLong()
            }
        } catch (e: Exception) {
            value = -1
        }
        return value
    }
}

StringAdapter.kt

package com.ziqi.baselibrary.util.gson

import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter

class StringAdapter : TypeAdapter<String?>() {
    override fun write(out: JsonWriter?, value: String?) {
        try {
            var tempValue: String? = value
            if (tempValue == null) {
                tempValue = ""
            }
            out?.value(tempValue)
        } catch (e: Exception) {

        }
    }

    override fun read(`in`: JsonReader?): String? {
        var value: String? = ""
        try {
            if (`in`?.peek() == JsonToken.NULL) {
                `in`.nextNull()
                value = ""
            } else if (`in`?.peek() == JsonToken.BOOLEAN) {
                val b = `in`.nextBoolean()
                value = b.toString()
            } else if (`in`?.peek() == JsonToken.NUMBER) {
                try {
                    value = `in`.nextLong().toString()
                } catch (e: Exception) {
                    value = ""
                }
            } else {
                value = `in`?.nextString()
            }
        } catch (e: Exception) {
            value = ""
        }
        return value
    }
}

解决了基本的类型,还有2个对象没处理

对象(JSON 对象)
数组

使用JsonDeserializer接口类,实现判断isJsonArrayisJsonObject
修改后的Gson对象代码

val gson: Gson = GsonBuilder() //配置你的Gson
        .setDateFormat("yyyy-MM-dd hh:mm:ss")
        //https://blog.csdn.net/axxbc123/article/details/84625539
        .enableComplexMapKeySerialization()
        //https://blog.csdn.net/u010502101/article/details/80555558
        .serializeNulls()
        .registerTypeAdapter(Int::class.java, IntAdapter())
        .registerTypeAdapter(Integer::class.java, IntAdapter())
        .registerTypeAdapter(String::class.java, StringAdapter())
        .registerTypeAdapter(Double::class.java, DoubleAdapter())
        .registerTypeAdapter(Long::class.java, LongAdapter())
        .registerTypeAdapter(List::class.java, ListJsonDeserializer())
        .registerTypeAdapter(TestData.A::class.java, ObjectJsonDeserializer<TestData.A>())
        .create()

ListJsonDeserializer.java

package com.ziqi.baselibrary.util.gson;

import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * https://www.jianshu.com/p/3108f1e44155
 */
public class ListJsonDeserializer implements JsonDeserializer<List<?>> {
    @Override
    public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonArray()) {
            JsonArray array = json.getAsJsonArray();
            Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
            List list = new ArrayList<>();
            for (int i = 0; i < array.size(); i++) {
                JsonElement element = array.get(i);
                Object item = context.deserialize(element, itemType);
                list.add(item);
            }
            return list;
        }
        return Collections.EMPTY_LIST;
    }
}

ObjectJsonDeserializer.java

package com.ziqi.baselibrary.util.gson;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class ObjectJsonDeserializer<T> implements JsonDeserializer<T> {
    @Override
    public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        T temp = null;
        if (json.isJsonObject()) {
            temp = GsonUtil.INSTANCE.getInnerGson().fromJson(json, typeOfT);
            return temp;
        }
        return temp;
    }
}

核心技术点是使用TypeAdapter和JsonDeserializer两个类处理,gson还有很多api可以让我学习的,若有更好的封装代码,希望大佬分享出来

经过以上处理gson后,不管后台返回对象是否正常,我们代码就会变得更健壮起来,最近我在写一个玩Android 这完整代码会在我GitHub上的工程上
WanAndroidKotlin
我是分了模块开发的,在baselibrary模块里面

转载请标明原处:https://www.jianshu.com/p/4a70eebedf68

相关文章

  • Android下谈谈Gson常见优化

    在 JSON 中,值必须是以下数据类型之一:字符串数字对象(JSON 对象)数组布尔NullJSON 的值不可以是...

  • Android性能优化之启动速度优化

    Android性能优化之启动速度优化 Android app 启动速度优化,首先谈谈为什么会走到优化这一步,如果一...

  • Android 内存优化&实践

    这是一篇关于Android 内存优化文章的摘要,原文见Android 内存优化总结&实践 一、Android常见内...

  • Android 库 Gson

    【Android 库 Gson】 引用: ★Gson 解析教程★★★ Gson的入门使用Gson全解析(上)-Gs...

  • [笔记]Android性能优化 中

    [笔记]Android性能优化 上[笔记]Android性能优化 中[笔记]Android性能优化 下 7.And...

  • [笔记]Android性能优化 下

    [笔记]Android性能优化 上[笔记]Android性能优化 中[笔记]Android性能优化 下 8.And...

  • [笔记]Android性能优化 上

    [笔记]Android性能优化 上[笔记]Android性能优化 中[笔记]Android性能优化 下 说明 这篇...

  • Andriod中Gson使用

    Gson使用 参考你真的会用Gson吗?Gson使用指南 在Android中使用Gson,先在Compile中加入...

  • Android性能优化

    1.Android性能优化-内存泄漏(上) 2.Android性能优化-内存泄漏(下) 3.Android性能优化...

  • Android 性能调优面试题

    1.1 谈谈你对Android性能优化方面的了解? 启动优化: application中不要做大量耗时操作,如果必...

网友评论

      本文标题:Android下谈谈Gson常见优化

      本文链接:https://www.haomeiwen.com/subject/oavrtktx.html