使用interface而不是class定义Retrofit返回类型

时间:2017-01-21 10:22:49

标签: android kotlin retrofit2

具有简单的Retrofit界面

interface Movies {
    @GET("movies/trending")
    fun trending(): Observable<List<TrendingMovie>>
}

是否可以将TrendingMovie定义为接口(结果将是Observable emititng实现此接口的匿名类列表)?

(我试过这样做,但我得到java.lang.IllegalArgumentException:没有JsonAdapter用于接口com.test.TrendingMovie)

1 个答案:

答案 0 :(得分:1)

是的,这肯定是可能的,但要求您为界面添加自定义反序列化器。这是通过为您使用的反序列化工具注册自定义类型反序列化器来完成的。

有了杰克逊(毕竟我会推荐用于与Kotlin课程一起工作),这是通过向Module添加ObjectMapper来完成的。以下是我使用jackson-module-kotlin执行此操作的步骤:

  1. 为您的界面添加Module创建自定义JsonDeserializer

    fun trendingMovieModule(): Module = SimpleModule().apply {
        val deserializer: JsonDeserializer<TrendingMovie> = object : JsonDeserializer<TrendingMovie>() {
            override fun deserialize(p: JsonParser, ctxt: DeserializationContext): TrendingMovie {
                val node = p.codec.readTree<JsonNode>(p)
    
                return object : TrendingMovie { // Your anonymous class here, for example:
                    val name = node["movie"]["title"]
                    val watchers = node["watchers"].intValue()
    
                    override fun toString(): String = "$name, watchers: $watchers"
                }
            }
        }
    
        addDeserializer(TrendingMovie::class.java, deserializer)
    }
    
  2. 使用ObjectMapper构建器Retrofit注册模块:

    val mapper = jacksonObjectMapper()
            .registerModule(trendingMovieModule())
    
  3. 使用mapper构建器中的Retrofit

    val r = Retrofit.Builder()
            // other necessary configuration omitted, e.g. custom OkHttpClient
            .baseUrl("https://api.trakt.tv")
            .addConverterFactory(JacksonConverterFactory.create(mapper))
            .build().create(Movies::class.java)
    

    JacksonConverterFactory需要依赖:converter-jackson

  4. 完成!它现在应该工作:

    r.trending().flatMap { Observable.from(it) }.forEach(::println)
    

    完整的源文件:(here)