Reputation: 77
So I'm trying to use themoviedb for extracting search results for movies. The url is as follows:
https://api.themoviedb.org/3/search/movie?api_key={apikey}&language=en-US&query={query}
Where in the query I insert the keyword that I want to search. I'm using retrofit library to do this.
This is my code for my ApiService:
interface ApiService {
@GET("3/search/movie?api_key=${BuildConfig.MOVIE_TOKEN}&language=en-US&")
fun getMovies(
@Query("query") query: String
): Call<SearchMovieResponse>
}
This is my code for the ApiConfig object:
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)
}
}
}
I also have a RemoteDataSouce
class which uses that config to get the movies. I have also generated the data class to using POJO. This is the method in the RemoteDataSource
class that uses that the API config.
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
}
The json response of the API is this:
The data model that I use for SearchMovieResponse
is this:
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
)
However, the listMovies is returning null. I'm not sure what I did wrong here. Can anyone explain? Thanks
Upvotes: 1
Views: 2146
Reputation: 6426
Try to use callback to return your list:
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
}
})
}
Upvotes: 1
Reputation: 1068
As, you are using enqueue() that run asynchronous so your function finish before the onResponse() method is called. So you have to return the list after on the complete of the process.
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
}
})
}
Upvotes: 1
Reputation: 1395
Your method getMovies()
is returning the list before the Retrofit call is done, you are using enqueue()
method that run it asynchronous so your method finish before the onResponse()
method is called.
Solution, rewrite your code thinking about this information or use execute()
method instead enqueue()
, this will execute the call in the main thread so you will have to call it in a new thread or a coroutine.
Upvotes: 3