0

I'm trying to get some data from an API and since I have this callback pointed to a null response, I get the following error:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.newsapp.develop, PID: 19479
    java.lang.NullPointerException: Attempt to invoke interface method 'boolean java.util.Collection.isEmpty()' on a null object reference
        at com.example.newsapp.API.NewsRemoteDataSource$getNewsList$1.onResponse(NewsRemoteDataSource.kt:21)
        at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
        at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$hVGjmafRi6VitDIrPNdoFizVAdk.run(Unknown Source:6)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7094)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)

How can I fix it while still keeping the functionality? That means, keeping the callback and also getting the results OnSuccess.

This is the adapter with the callback:

package com.example.newsapp.Adapters

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.newsapp.ArticlesData
import com.example.newsapp.R
import com.example.newsapp.databinding.NewsItemBinding
import com.squareup.picasso.Picasso

class RecyclerAdapter (private var Articles: List<ArticlesData>) : RecyclerView.Adapter<RecyclerAdapter.ViewHolder>(){

    inner class ViewHolder(
        view: View
    ): RecyclerView.ViewHolder(view){
        private val binding = NewsItemBinding.bind(view)

        val itemTitle: TextView = binding.tvTitle
        val itemImage: ImageView = binding.ivNewsImage

        fun bind(articles: ArticlesData){
            Picasso.get().load(articles.urlToImage).into(binding.ivNewsImage)
            itemTitle.text = articles.Title
        }
    }

    interface Callback {
        fun onArticleClicked(articleClicked: ArticlesData)
    }

    var callback: Callback? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.news_item, parent, false)
        return ViewHolder(v)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(Articles[position])

        holder.itemImage.setOnClickListener {
            callback?.onArticleClicked(Articles[position])
        }

    }

    override fun getItemCount(): Int {
        return Articles.size
    }

    fun setNewsList(newList: List<ArticlesData>) {
        this.Articles = newList
        notifyDataSetChanged()
    }


}

This is the remote data source where the issue comes from:

package com.example.newsapp.API

import com.example.newsapp.ArticlesData
import com.example.newsapp.NewsListResponse
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class NewsRemoteDataSource {
    fun getNewsList(networkResponse: NetworkResponse<List<ArticlesData>>) {
        val service = RetrofitServices.instance
            .create(APIService::class.java)
            .getNewsList()

        service.enqueue(object : Callback<NewsListResponse> {
            override fun onResponse(
                call: Call<NewsListResponse>,
                response: Response<NewsListResponse>
            ) {
                val resource = response.body()?.run {
                    if (results.isNotEmpty())
                        Resource(NetworkStatus.SUCCESS, results)
                    else
                        Resource(NetworkStatus.ERROR)
                } ?: run {
                    Resource(NetworkStatus.ERROR)
                }
                networkResponse.onResponse(resource)
            }

            override fun onFailure(call: Call<NewsListResponse>, t: Throwable) {
                networkResponse.onResponse(Resource(NetworkStatus.ERROR, message = t.message))
            }
        })
    }


}

interface NetworkResponse<T> {
    fun onResponse(value: Resource<T>)
}

API response:

data class NewsResponse (
    @SerializedName("status") var Status: String,
    @SerializedName("totalResults") var totalResults: Int,
    @SerializedName("articles") var Articles: List<ArticlesData>
    )

@Parcelize
data class ArticlesData (
    @SerializedName("source") var Source: @RawValue SourceData,
    @SerializedName("author") var Author: String? = " ",
    @SerializedName("title") var Title: String,
    @SerializedName("description") var Description: String,
    @SerializedName("url") var Url: String,
    @SerializedName("urlToImage") var urlToImage: String? =" ",
    @SerializedName("publishedAt") var publishedAt: String,
    @SerializedName("content") var Content: String? = " "
) : Parcelable

data class SourceData (
    @SerializedName("name") var Name: String,
)

data class NewsListResponse(
    val results: List<ArticlesData>
)
dazai
  • 766
  • 4
  • 25
  • I dont see anywhere where `results` is actually set to anything – tyczj Aug 10 '21 at 17:17
  • Since you're using a Response you can check the response code: https://stackoverflow.com/questions/31808083/how-to-get-retrofit-success-response-status-codes – Daniel Nugent Aug 10 '21 at 17:22
  • @tyczj I added info about the api response – dazai Aug 10 '21 at 17:22
  • @DanielNugent I can see in the debugging response that the result is not null: I/okhttp.OkHttpClient: <-- 200 (and all the news follow) – dazai Aug 10 '21 at 17:24

2 Answers2

0

set results?.isNotEmpty() == true this is causing exception because results could be null

Saurabh Dhage
  • 1,478
  • 5
  • 17
  • 31
0

For some reason result seems to be null, you need to modify your if condition as

if (results.isNullOrEmpty())
    Resource(NetworkStatus.ERROR)
else
    Resource(NetworkStatus.SUCCESS, results)
mightyWOZ
  • 7,946
  • 3
  • 29
  • 46
  • If I do that, it just goes into error but I've had this code working before I can see in the logs that the results are not null – dazai Aug 10 '21 at 17:36