【问题标题】:Why is my retrofit model returns null? Android Kotlin为什么我的改造模型返回 null?安卓科特林
【发布时间】:2021-07-21 16:24:47
【问题描述】:

所以我正在尝试使用 themoviedb 来提取电影的搜索结果。网址如下:

https://api.themoviedb.org/3/search/movie?api_key={apikey}&language=en-US&query={query}

我在查询中插入要搜索的关键字的位置。我正在使用改造库来做到这一点。

这是我的 ApiService 代码:

interface ApiService {
    @GET("3/search/movie?api_key=${BuildConfig.MOVIE_TOKEN}&language=en-US&")
    fun getMovies(
        @Query("query") query: String
    ): Call<SearchMovieResponse>
}

这是我的 ApiConfig 对象代码:

class ApiConfig {
companion object {
    fun getApiService(): ApiService{
        val loggingInterceptor =
            HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
        val client = OkHttpClient.Builder()
            .addInterceptor(loggingInterceptor)
            .build()
        val retrofit = Retrofit.Builder()
            .baseUrl("https://api.themoviedb.org/")
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build()
        return retrofit.create(ApiService::class.java)
    }
}

}

我还有一个 RemoteDataSouce 类,它使用该配置来获取电影。我还生成了使用 POJO 的数据类。这是 RemoteDataSource 类中使用该 API 配置的方法。

fun getMovies():List<MoviesItem>?{
    val client = ApiConfig.getApiService().getMovies("john")
    var listMovies: ArrayList<MoviesItem> = ArrayList<MoviesItem>()
    client.enqueue(object: Callback<SearchMovieResponse> {
        override fun onResponse(call: Call<SearchMovieResponse>, response: Response<SearchMovieResponse>) {
            if (response.isSuccessful){
                val rawList = response.body()?.results!!
                for (item in rawList){
                    listMovies.add(item)
                }
            }
        }
        override fun onFailure(call: Call<SearchMovieResponse>, t: Throwable) {
            return
        }

    })
    return listMovies
}

API 的 json 响应是这样的:

我用于SearchMovieResponse 的数据模型是这样的:

data class SearchShowResponse(

@field:SerializedName("page")
val page: Int? = null,

@field:SerializedName("total_pages")
val totalPages: Int? = null,

@field:SerializedName("results")
val results: List<ShowsItem?>? = null,

@field:SerializedName("total_results")
val totalResults: Int? = null
)

data class ShowsItem(

@field:SerializedName("first_air_date")
val firstAirDate: String? = null,

@field:SerializedName("overview")
val overview: String? = null,

@field:SerializedName("original_language")
val originalLanguage: String? = null,

@field:SerializedName("genre_ids")
val genreIds: List<Int?>? = null,

@field:SerializedName("poster_path")
val posterPath: String? = null,

@field:SerializedName("origin_country")
val originCountry: List<String?>? = null,

@field:SerializedName("backdrop_path")
val backdropPath: String? = null,

@field:SerializedName("original_name")
val originalName: String? = null,

@field:SerializedName("popularity")
val popularity: Double? = null,

@field:SerializedName("vote_average")
val voteAverage: Double? = null,

@field:SerializedName("name")
val name: String? = null,

@field:SerializedName("id")
val id: Int? = null,

@field:SerializedName("vote_count")
val voteCount: Int? = null
)

但是,listMovies 返回 null。我不确定我在这里做错了什么。谁能解释一下?谢谢

【问题讨论】:

  • 显示 json 和 SearchMovieResponse
  • @shmakova 我刚刚编辑了问题

标签: android kotlin retrofit retrofit2


【解决方案1】:

您的方法 getMovies() 在 Retrofit 调用完成之前返回列表,您正在使用异步运行它的 enqueue() 方法,因此您的方法在调用 onResponse() 方法之前完成。

解决方案,考虑此信息重写您的代码或使用execute()method 代替enqueue(),这将在主线程中执行调用,因此您必须在新线程或协程中调用它。

【讨论】:

  • 有什么方法可以在 enqueue 方法中返回它?
  • @BrianMohammedCatraguna 最简单的方法是在 onResponse() 方法中更新数据的适配器,使用空数组启动 recyclerview,然后在 onResponse 方法完成时,使用真实的适配器更新适配器数据。
【解决方案2】:

因为,您正在使用运行 异步 的 enqueue(),因此您的函数在调用 onResponse() 方法之前完成。因此,您必须在完成该过程后返回列表。

 fun getMovies():List<MoviesItem>?{
        val client = ApiConfig.getApiService().getMovies("john")
        var listMovies: ArrayList<MoviesItem> = ArrayList<MoviesItem>()
        client.enqueue(object: Callback<SearchMovieResponse> {
            override fun onResponse(call: Call<SearchMovieResponse>, response: Response<SearchMovieResponse>) {
                if (response.isSuccessful){
                    val rawList = response.body()?.results!!
                    for (item in rawList){
                        listMovies.add(item)
                    }
                  return listMovies
    
                }
            }
            override fun onFailure(call: Call<SearchMovieResponse>, t: Throwable) {
                return
            }
    
        })
    }

【讨论】:

  • 当我将 return 放入 if 块中时,我收到一条错误消息,指出它需要 Unit 而不是 kotlin.collections.ArrayList
  • 是的,函数需要一些回报。从函数中删除 return 并将您的列表添加到我放置 return 的位置。
  • 对不起,我不太明白你从函数中删除返回的意思。那么我要恢复到我之前的代码吗?添加列表是指添加到 listMovies 吗?
  • 首先告诉我,在你得到你要设置的列表之后。你要设置recyclerview吗?
  • 是的,我正打算这样做。现在我只是想尝试连接是否有效,我只是从列表中获取一个项目,并在 textview 上设置该项目的一个属性。
【解决方案3】:

尝试使用回调来返回您的列表:

fun getMovies(callback: (List<MoviesItem>) -> Unit) {
    val client = ApiConfig.getApiService().getMovies("john")
    client.enqueue(object : Callback<SearchMovieResponse> {
        override fun onResponse(
            call: Call<SearchMovieResponse>,
            response: Response<SearchMovieResponse>
        ) {
            var listMovies: ArrayList<MoviesItem> = ArrayList<MoviesItem>()
            if (response.isSuccessful) {
                val rawList = response.body()?.results!!
                for (item in rawList) {
                    listMovies.add(item)
                }
            }
            callback(listMovies)
        }

        override fun onFailure(call: Call<SearchMovieResponse>, t: Throwable) {
            callback(emptyList()) // or throw error or use Result structure
        }

    })
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-23
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多