欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android如何解析異構(gòu)列表

 更新時(shí)間:2021年03月19日 09:12:55   作者:benio  
這篇文章主要介紹了Android如何解析異構(gòu)列表,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下

前言

開發(fā)業(yè)務(wù)需求時(shí),遇到了列表中包含完全不同類型的數(shù)據(jù)結(jié)構(gòu)。這種列表我們稱為異構(gòu)列表。以聊天記錄列表為例

[
	{
		"msgType" : "text",
		"id" : "1",
		"content" : "Hello world"
	},
	{
		"msgType" : "record",
		"id" : "2",
		"url" : "https://xxxx.mp4",
		"length" : 123450
	},
	{
		"msgType" : "image",
		"id" : "3",
		"url" : "https://xxxx.jpg",
		"size" : "300x300"
	}
]

要想解析上面的JSON,手動(dòng)解析不是不行,但肯定不推薦。如果直接使用解析工具,比如用Gson來解析的話,無論定義什么樣的數(shù)據(jù)結(jié)構(gòu)好像都不符合上面的列表元素。

那可不可以做到,我們告訴Gson列表中各個(gè)元素分別是什么樣的數(shù)據(jù)類型,這樣它不就知道該怎么解析了嗎?接下來我們通過Gson的TypeAdapter來實(shí)現(xiàn)自定義解析。

實(shí)現(xiàn)方案

先定義好各種數(shù)據(jù)類型,與msgType字段一一對(duì)應(yīng)

abstract class BaseMessage(val id: String?, val msgType: String?)

class TextMessage(id: String?, msgType: String?, val content: String?
) : BaseMessage(id, msgType)

class ImageMessage(id: String?, msgType: String?, val url: String?, val size: String?
) : BaseMessage(id, msgType)

class RecordMessage(id: String?, msgType: String?, val url: String?, val length: Long
) : BaseMessage(id, msgType)

接著自定義一個(gè)TypeAdapter。

class BaseMessageTypeAdapter : TypeAdapter<BaseMessage>() {
 override fun write(out: JsonWriter, value: BaseMessage?) {
 }

 override fun read(`in`: JsonReader): BaseMessage? {
 }
}

可以看到里面有兩個(gè)方法:write()負(fù)責(zé)序列化,read()負(fù)責(zé)反序列化。我們先重點(diǎn)關(guān)注read()的實(shí)現(xiàn)

實(shí)現(xiàn)read()的基本思路如下

  1. 讀取msgType字段
  2. 根據(jù)msgType判斷對(duì)應(yīng)的數(shù)據(jù)類型
  3. 根據(jù)該數(shù)據(jù)類型獲取解析該類型的TypeAdapter
  4. 交給對(duì)應(yīng)類型的TypeAdapter解析

依照上述思路,可以寫出read()的基本實(shí)現(xiàn)代碼。當(dāng)然這是比較粗糙的實(shí)現(xiàn),實(shí)際上還有其他情況要考慮

class BaseMessageTypeAdapter(private val gson: Gson, 
        private val skipPast: TypeAdapterFactory
) : TypeAdapter<BaseMessage>() {
 override fun read(`in`: JsonReader): BaseMessage? {
  // 1.讀取msgType字段
  val jsonObject = Streams.parse(`in`).asJsonObject
  val msgType = jsonObject.get("msgType")?.asString
  // 2.根據(jù)msgType獲取解析該類型的TypeAdapter
  val adapter = getTypeAdapterByType(msgType)
  // 3.交給對(duì)應(yīng)類型的TypeAdapter解析
  return adapter?.fromJsonTree(jsonObject)
 }
}

write()方法沒什么好說的,直接交給對(duì)應(yīng)類型的TypeAdapter序列化

class BaseMessageTypeAdapter(private val gson: Gson, 
        private val skipPast: TypeAdapterFactory
) : TypeAdapter<BaseMessage>() {
 override fun write(out: JsonWriter, value: BaseMessage?) {
  if (value == null) {
   out.nullValue()
   return
  }
  getTypeAdapterByType(value.msgType)?.write(out, value)
 }
}

接著就是實(shí)現(xiàn)getTypeAdapterByType()方法。

 private fun getTypeAdapterByType(type: String?): TypeAdapter<BaseMessage>? {
  return when (type) {
   "text" -> getTypeAdapter(TextMessage::class.java)
   "image" -> getTypeAdapter(ImageMessage::class.java)
   "record" -> getTypeAdapter(RecordMessage::class.java)
   else -> null
  }
 }

 private fun <R : BaseMessage> getTypeAdapter(clazz: Class<R>): TypeAdapter<BaseMessage> {
  // 獲取Gson中該類型對(duì)應(yīng)的TypeAdapter
  return SubTypeAdapterWrapper(clazz, gson.getDelegateAdapter(skipPast, TypeToken.get(clazz)))
 }

邏輯也比較簡單。需要注意的是,在getTypeAdapter()方法中,要將TypeAdapter<out BaseMessage>轉(zhuǎn)換成TypeAdapter<BaseMessage>。接下來我們看看SubTypeAdapterWrapper是怎樣實(shí)現(xiàn)的

class SubTypeAdapterWrapper<T, R : T>(private val clazz: Class<R>,
          private val adapter: TypeAdapter<R>
) : TypeAdapter<T>() {
 override fun write(out: JsonWriter, value: T) {
  if (!clazz.isInstance(value)) {
   throw JsonSyntaxException("Expected a " + clazz.name + " but was " + value)
  }
  adapter.write(out, value as R)
 }

 override fun read(`in`: JsonReader): T {
  return adapter.read(`in`)
 }
}

其實(shí)就是一個(gè)包裝類。將解析R類型的TypeAdapter包裝成解析T類型的TypeAdapter。

最后就是實(shí)現(xiàn)一個(gè)TypeAdapterFactory,并將其注冊(cè)到Gson

class BaseMessageTypeAdapterFactory : TypeAdapterFactory {
 override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
  if (!BaseMessage::class.java.isAssignableFrom(type.rawType)) {
   return null
  }
  return BaseMessageTypeAdapter(gson, this) as (TypeAdapter<T>)
 }
}

寫個(gè)測(cè)試用例測(cè)試一下

抽象封裝

為了更好的復(fù)用,接下來我們要對(duì)BaseMessageTypeAdapter改造一下。

定義一個(gè)新的TypeAdapter子類。將類型和TypeAdapter的關(guān)系用Map來存儲(chǔ),并提供方法給外部調(diào)用。

public class HeterogeneousTypeAdapter<T> extends TypeAdapter<T> {
 private final Gson mGson;
 private final TypeAdapterFactory mSkipPast;
 private final String mFieldName;
 private final Map<String, TypeAdapter<T>> mClassToAdapterMap = new HashMap<>();
 private final Map<String, TypeAdapter<T>> mFieldToAdapterMap = new HashMap<>();

 public HeterogeneousTypeAdapter(Gson gson, TypeAdapterFactory skipPast, String fieldName) {
  mGson = gson;
  mSkipPast = skipPast;
  mFieldName = fieldName;
 }

 public <R extends T> void addSubTypeAdapter(final String fieldValue,
            final Class<R> cls) {
  final TypeAdapter<R> typeAdapter = mGson.getDelegateAdapter(mSkipPast, TypeToken.get(cls));
  addSubTypeAdapter(fieldValue, cls, typeAdapter);
 }

 public <R extends T> void addSubTypeAdapter(final String fieldValue,
            final Class<R> cls,
            final TypeAdapter<R> typeAdapter) {
  final TypeAdapter<T> adapter = new SubTypeAdapterWrapper<>(cls, typeAdapter);
  mClassToAdapterMap.put(cls.getName(), adapter);
  mFieldToAdapterMap.put(fieldValue, adapter);
 }

 @Override
 public void write(JsonWriter out, T value) throws IOException {
  if (value == null) {
   out.nullValue();
   return;
  }
  getTypeAdapterByClass(value.getClass()).write(out, value);
 }

 @Override
 public T read(JsonReader in) throws IOException {
  if (in.peek() == JsonToken.NULL) {
   in.nextNull();
   return null;
  }

  final JsonObject jsonObject = Streams.parse(in).getAsJsonObject();
  final JsonElement fieldElement = jsonObject.get(mFieldName);
  if (fieldElement == null || fieldElement.isJsonNull()) {
   throw new JsonSyntaxException("Field " + mFieldName + " is null or not found");
  }

  final String field = fieldElement.getAsJsonPrimitive().getAsString();
  final TypeAdapter<T> adapter = getTypeAdapterByField(field);
  if (adapter == null) {
   // Unknown field, just skip
   return null;
  }
  return adapter.fromJsonTree(jsonObject);
 }

 private TypeAdapter<T> getTypeAdapterByClass(Class<?> cls) {
  TypeAdapter<T> adapter = mClassToAdapterMap.get(cls.getName());
  if (adapter == null) {
   throw new JsonParseException("Unknown class : " + cls);
  }
  return adapter;
 }

 private TypeAdapter<T> getTypeAdapterByField(String field) {
  return mFieldToAdapterMap.get(field);
 }
}

使用方式

class BaseMessageTypeAdapterFactory : TypeAdapterFactory {
 override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
  if (!BaseMessage::class.java.isAssignableFrom(type.rawType)) {
   return null
  }
  val adapter = HeterogeneousTypeAdapter<BaseMessage>(gson, this, "msgType")
  // 注冊(cè)各種類型
  adapter.addSubTypeAdapter("text", TextMessage::class.java)
  adapter.addSubTypeAdapter("image", ImageMessage::class.java)
  adapter.addSubTypeAdapter("record", RecordMessage::class.java)
  return adapter as (TypeAdapter<T>)
 }
}

總結(jié)

通過自定義TypeAdapter,我們實(shí)現(xiàn)了解析異構(gòu)列表的功能。免除手動(dòng)解析的繁瑣工作,避免出現(xiàn)不必要的錯(cuò)誤。

以上就是Android如何解析異構(gòu)列表的詳細(xì)內(nèi)容,更多關(guān)于Android 解析異構(gòu)列表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論