androidkotlinomdbapi

OMDb Api doesn't show any result - Kotlin, Android Studio


I followed everything carefully, step by step, but I can't find what the problem is. Whenever I fill in the name of the movie I intend to search by, the app crashes and it says this: java.lang.NullPointerException: response.body() must not be null

Does anyone have any idea? Here is the following code.

MovieList.kt

class MovieList {
    val imdbID: String
    val Title: String
    val Year: String
    val Plot: String
    val Poster: String

    constructor(imdbID: String, Title: String, Year: String, Plot: String, Poster: String) {
        this.imdbID = imdbID
        this.Title = Title
        this.Year = Year
        this.Plot = Plot
        this.Poster = Poster
    }
}

OMDbApi.kt

interface OMDbApi {
    @GET("t={Title}")
    fun getMovieByTitle(@Path("Title") Title: String): Call<MovieList>
}

OMDbApiClient.kt

class OMDbApiClient {

    companion object{
        private var omdbapi: OMDbApi? = null

        fun getOMDbApi(): OMDbApi?{
            if(omdbapi == null){
                omdbapi = Retrofit.Builder()
                    .baseUrl("http://www.omdbapi.com/?&apikey=eb73867f")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
                    .create(OMDbApi::class.java);

            }

            return omdbapi
        }

    }

}

FirstFragment.kt

class FirstFragment : Fragment() {
    private lateinit var omdbapiClient: OMDbApi
    private lateinit var tvMovieTitle: TextView
    private lateinit var ivImagePoster: ImageView

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_first, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        omdbapiClient = OMDbApiClient.getOMDbApi()!!

        val movieId: EditText = view.findViewById<EditText>(R.id.TitleId)

        tvMovieTitle = view.findViewById(R.id.MovieTitleId)
        ivImagePoster = view.findViewById(R.id.MoviePosterId)

        movieId.setOnEditorActionListener { v, actionId, event ->
            if(actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_NEXT){
                val movietitle: String = movieId.text.toString()
                searchMovieByTitle(movietitle)
                true
            }
            else{
                Toast.makeText(activity, "Error!", Toast.LENGTH_LONG).show()
                false
            }
        }
    }

    private fun searchMovieByTitle(movietitle: String) {
        omdbapiClient.getMovieByTitle(movietitle).enqueue(object : Callback<MovieList>{
            override fun onResponse(call: Call<MovieList>?, response: Response<MovieList>) {
                displayData(response.body())
                Toast.makeText(activity, "Success!", Toast.LENGTH_LONG).show()
            }

            override fun onFailure(call: Call<MovieList>?, t: Throwable?) {
                Toast.makeText(activity, "Error!", Toast.LENGTH_LONG).show()
            }

        })
    }

    private fun displayData(data: MovieList) {
        tvMovieTitle.text = data.Title
        Glide.with(this).load(data.Poster).into(ivImagePoster)
    }


}

Solution

  • I think you are getting an error response and that's why the response.body() is null. You should be handling an error response gracefully, instead of expecting the body to always not be null, but that is another matter.

    I think the following lines of code are at fault:

    interface OMDbApi {
        @GET("t={Title}")
        fun getMovieByTitle(@Path("Title") Title: String): Call<MovieList>
    }
    

    The 'Title' should be a @Query parameter instead of a @Path parameter, because the &t= part in the API url is a query parameter. When it is a query parameter you also don't specify it as part of the path in @GET.

    Your code would then become:

    interface OMDbApi {
        @GET("")
        fun getMovieByTitle(@Query("t") title: String): Call<MovieList>
    }
    

    Do this change and see if you still get an error response. You might want to check the log in the 'Logcat' tab to see what error you are getting back from the API.

    For that you might have to enable a higher logging level. This is done by adding a logging interceptor when building the Retrofit client.

        // Build a http client with logging enabled
        val client = OkHttpClient.Builder()
            .addInterceptor(HttpLoggingInterceptor().apply {
                // you can also use Level.BODY for even more log information
                level = HttpLoggingInterceptor.Level.BASIC
            })
            .build()
        
        omdbapi = Retrofit.Builder()
            .client(client) // add this line to use your http client
            .baseUrl("http://www.omdbapi.com/?&apikey=eb73867f")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(OMDbApi::class.java);