Как я могу получить указанный c JSON массив из ответа, используя Retrofit2 и GSON? - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь получить некоторые данные в формате JSON, используя Retrofit, и мне нужен только конкретный массив c из ответа. Как я могу сделать это с помощью GSON? Например, в приведенном ниже примере требуется только массив «статьи».


status: "ok",
totalResults: 970843,
articles: [
{
   ...,
   ...,
   ...
},

1 Ответ

0 голосов
/ 11 апреля 2020

Вы можете создать собственный десериализатор для этого конкретного случая, или (и этот второй вариант, который я опишу), есть более универсальное c решение, которое требует немного больше усилий, но хорошо окупится в долгосрочной перспективе, как вы могли бы применить его для других подобных случаев использования. Это мой любимый подход, я сталкивался с ним на GitHub (я не изобретатель) - и принял его для себя - вы можете проверить код и проект, чтобы понять, как все это работает вместе - ссылка на проект

Ниже я извлек соответствующие части:

  1. Создайте специальную фабрику конвертеров следующим образом:
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import okhttp3.ResponseBody
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type

/**
 * A [Converter.Factory] which removes unwanted wrapping envelopes from API
 * responses.
 */
class DenvelopingConverter(internal val gson: Gson) : Converter.Factory() {

    override fun responseBodyConverter(
            type: Type, annotations: Array<Annotation>?, retrofit: Retrofit?): Converter<ResponseBody, *>? {

        // This converter requires an annotation providing the name of the payload in the envelope;
        // if one is not supplied then return null to continue down the converter chain.
        val payloadName = getPayloadName(annotations) ?: return null

        val adapter = gson.getAdapter(TypeToken.get(type))
        return Converter<ResponseBody, Any> { body ->
            try {
                val jsonReader = gson.newJsonReader(body.charStream())
                jsonReader.beginObject()
                while (jsonReader.hasNext()) {
                    if (payloadName == jsonReader.nextName()) {
                        return@Converter adapter.read(jsonReader)
                    } else {
                        jsonReader.skipValue()
                    }
                }
                return@Converter null
            } finally {
                body.close()
            }
        }
    }

    private fun getPayloadName(annotations: Array<Annotation>?): String? {
        if (annotations == null) {
            return null
        }
        for (annotation in annotations) {
            if (annotation is EnvelopePayload) {
                return annotation.value
            }
        }
        return null
    }
}
Создать этот класс аннотаций
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME)
annotation class EnvelopePayload(val value: String = "")
В своем модификаторе сборки добавьте преобразователь, созданный на шаге 1
  return Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(DenvelopingConverter(gson))
В своем интерфейсе модернизации используйте @EnvelopePayload, который вы создали на шаге 2, чтобы отфильтровать нужные вам элементы, в вашем случае, «статьи», например:
interface MyService {

    @EnvelopePayload("articles")
    @GET("whatever")
    //fun search....
}

Это это, наслаждайтесь!

...