前言
本文章只讨论解决空值以及默认值问题,不做框架中序列化和序列化的所使用方法以及优劣性进行分析,如有需要请自己研究
问题描述
我们平常在做网络请求时候,当后台服务器需要返回一个用户数据的时候,假如返回的是 username 和 phoneNumber,根据这个我们轻松写出下面的对象类:
data class UserBean(val userName:String,val phoneNumber:String)
用做来网络解析美滋滋,瞬间就可以Ok,想着可以提测上线早下班,然而还是想少了,想不到服务器不靠谱,直接给你返回一个:
{"userName":"User1"}
然后你发现你炸了,直接解析异常或者闪退了,这时候你气冲冲的找服务器理论,为啥电话号码字段没有了
-
服务器:产品要求的,电话号码可以为空。 -
你:那你应该返回这个字段啊! -
服务器:都为空了我返回干嘛,你自己解决。
听到这你也只能自己解决了,修改一下变成以下代码,为了防止其他字段为空,你就要把所有代码都加上可空的标识
data class UserBean(val userName:String?,val phoneNumber:String?)
这样虽说解决了问题,但是在参数比较多的时候,你会发现全是?,而且在使用的时候各种判断空 至于为啥要全部加?就是因为服务器实在是信不过,直接给你来个幺儿子
解决办法
鉴于这种情况,谷歌原生其实有专门的框架可以解决 kotlinx-serialization ,但是kotlinx-serialization需要注解,而且只支持kt,使用起来会稍微麻烦一点。 既然说是王者归来,那肯定不是用kotlinx-serialization解决了,今天的主角是Moshi,你没听错,就是Okhttp公司出品的Moshi,前两年我用Moshi的时候,也还是和kotlinx-serialization一样需要用注解,但现在已经完全不需要了,用起来及其方便,而且完全解决问题
重要的事情说三遍:不需要注解,不需要注解,不需要注解,直接服用
下面会写出kotlinx-serialization和Moshi 还有 FastJson序列化已经反序列的用法,结果请自己验证一下,只有moshi和kotlinx-serialization支持默认值的,不过kotlinx-serialization需要注解,moshi不需要
在写代码前先抽离一下序列化和反序列化的方法,以及测试的方法,后面替换可以直接用:
/**
*序列化拓展函数
**/
fun Any?.toJson(): String {
return ""
}
/**
*反序列化拓展函数
**/
fun String?.fromJsonString(): T? {
return null
}
验证的函数
data class TestBean(var test1: String = "", val test2: String = "")
fun testFun(){
val testBean = TestBean("testStr1")
testBean.toJson().logE("测试序列化")
"{"test1":"111"}".fromJsonString<TestBean>().logE("测试反序列化,没字段")
"{}".fromJsonString<TestBean>().logE("测试反序列化,测试都没有值")
}
Moshi
导包
implementation 'com.squareup.moshi:moshi-kotlin:1.13.0'
修改一下上面的序列化函数
val moshi by lazy {
Moshi.Builder()
.addLast(KotlinJsonAdapterFactory())
.build()
}
/**
*序列化拓展函数
**/
fun Any?.toJson(): String {
return try {
moshi.adapter(this::class.java).toJson(this)
} catch (e: Throwable) {
e.log()
""
}
}
/**
*反序列化拓展函数
**/
fun String?.fromJsonString(): T? {
return try {
if (this.isNullOrBlank()) null else {
moshi.adapter(T::class.java).fromJson(this)
}
} catch (e: Throwable) {
e.log()
null
}
}
可以快乐去验证了
kotlinx-serialization
导包
//根目录的build.gradle添加
classpath "org.jetbrains.kotlin:kotlin-serialization:1.6.0"
//项目build.gradle添加
id 'kotlinx-serialization'
implementation="org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
再次修改上面的序列化函数
val jsonDecoder = Json {
prettyPrint = false
isLenient = true
ignoreUnknownKeys = true // JSON和数据模型字段可以不匹配
coerceInputValues = true // 如果JSON字段是Null则使用默认值
allowStructuredMapKeys = true //启用Map序列化(默认情况是不能序列化Map)\
explicitNulls = true
encodeDefaults = true
}
/**
*序列化拓展函数
**/
fun Any?.toJson(): String {
return try {
jsonDecoder.encodeToString(this)
} catch (e: Throwable) {
e.log()
""
}
}
/**
*反序列化拓展函数
**/
fun String?.fromJsonString(): T? {
return try {
if (this.isNullOrBlank()) null else {
jsonDecoder.decodeFromString(this)
}
} catch (e: Throwable) {
e.log()
null
}
}
最重要的,要加注解,要不然会报异常
@Serializable
data class TestBean(var test1: String = "", val test2: String = "")
可以快乐去验证了
FastJson
fastjson已经出FastJson2了,不过还是很多bug,建议还是使用1
修改上面的方法
/**
*序列化拓展函数
**/
fun Any?.toJson(): String {
return try {
JSON.toJSONString(this)
} catch (e: Throwable) {
e.log()
""
}
}
/**
*反序列化拓展函数
**/
fun String?.fromJsonString(): T? {
return try {
if (this.isNullOrBlank()) null else {
JSON.parseObject(this,object : TypeReference<T>() {})
}
} catch (e: Throwable) {
e.log()
null
}
}
去快乐的验证吧