1

This is my Adapter class. when I open recycler view, if the list is null app crashes otherwise app run smoothly. I think I have to do something with the list. I mean if it's null do something that can prevent the app from being crashed. can anybody help me out?

class adsAdapter(
    private val adsList: List<adsModel>,
    private val listener: ManageAdsFragment
    ): RecyclerView.Adapter<adsAdapter.adsViewHolder>(){


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

    override fun onBindViewHolder(holder: adsViewHolder, position: Int) {
        holder.title.text = adsList[position].title
        val quantity =  adsList[position].quantity
        val watched = adsList[position].watched
        val adData =  "$watched/$quantity"
        holder.adsData.text = adData
        val status: String = adsList[position].status.toString()
        when{
            status == "1" -> {
                holder.onlineImageView.visibility = View.VISIBLE
                holder.completeImageView.visibility = View.INVISIBLE
                holder.cancelImageView.visibility = View.INVISIBLE
            }
            status == "2" -> {
                holder.onlineImageView.visibility = View.INVISIBLE
                holder.completeImageView.visibility = View.VISIBLE
                holder.cancelImageView.visibility = View.INVISIBLE
            }
            status == "3" ->{
                holder.onlineImageView.visibility = View.INVISIBLE
                holder.completeImageView.visibility = View.INVISIBLE
                holder.cancelImageView.visibility = View.VISIBLE
            }
        }
    }

    override fun getItemCount() = adsList.size

    inner class adsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
    ,View.OnClickListener{
        val onlineImageView: ImageView = itemView.findViewById(R.id.onlineImageView)
        val completeImageView: ImageView = itemView.findViewById(R.id.completeImageView)
        val cancelImageView: ImageView = itemView.findViewById(R.id.cancelImageView)
        var adsData: TextView = itemView.findViewById<TextView>(R.id.adsDataTextView)
        var title: TextView = itemView.findViewById<TextView>(R.id.titleTextView)
        init {
            itemView.setOnClickListener(this)
        }

        override fun onClick(v: View?) {
            val position: Int = adapterPosition
            if (position != RecyclerView.NO_POSITION) {
                listener.onItemClick(position)
            }
        }
    }

    interface OnItemClickListener{
        fun onItemClick(position: Int)
    }


}

Here are the logcat

2021-08-27 06:13:42.176 2355-2411/com.crazybot.rewardoomadvertiser D/EGL_emulation: eglMakeCurrent: 0x98714a40: ver 2 0 (tinfo 0x853620a0)
2021-08-27 06:13:42.212 2355-2360/com.crazybot.rewardoomadvertiser I/art: Do partial code cache collection, code=61KB, data=62KB
2021-08-27 06:13:42.215 2355-2360/com.crazybot.rewardoomadvertiser I/art: After code cache collection, code=60KB, data=62KB
2021-08-27 06:13:42.215 2355-2360/com.crazybot.rewardoomadvertiser I/art: Increasing code cache capacity to 256KB
2021-08-27 06:13:42.528 2355-2396/com.crazybot.rewardoomadvertiser D/FA: Connected to remote service
2021-08-27 06:13:42.529 2355-2396/com.crazybot.rewardoomadvertiser V/FA: Processing queued up service tasks: 5
2021-08-27 06:13:44.068 2355-2355/com.crazybot.rewardoomadvertiser E/RecyclerView: No adapter attached; skipping layout
2021-08-27 06:13:44.081 2355-2355/com.crazybot.rewardoomadvertiser D/AndroidRuntime: Shutting down VM
2021-08-27 06:13:44.083 2355-2355/com.crazybot.rewardoomadvertiser E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.crazybot.rewardoomadvertiser, PID: 2355
    java.lang.NullPointerException: null cannot be cast to non-null type kotlin.collections.List<com.crazybot.rewardoomadvertiser.model.adsModel>
        at com.crazybot.rewardoomadvertiser.ui.fragment.ManageAdsFragment$getData$1.onResponse(ManageAdsFragment.kt:58)
        at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
        at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1$$ExternalSyntheticLambda1.run(Unknown Source)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

The funtion in ManageAdsFragment(where I'm getting the data for recycler view) and lastly I use retrofit to get the data from a rest API. while I used firebase with recycler view I didn't get this type of error

 private fun getData() {
        val uid = auth.uid.toString()
        val call: Call<List<adsModel?>?>? = apiController
            .instance?.api?.getAds(uid)
        call?.enqueue(object : Callback<List<adsModel?>?>{
            override fun onResponse(
                call: Call<List<adsModel?>?>,
                response: Response<List<adsModel?>?>
            ) {
                obj = response.body()
                val adapter: adsAdapter = adsAdapter(obj as List<adsModel>, this@ManageAdsFragment)
                binding.recyclerview.layoutManager = LinearLayoutManager(requireContext())
                binding.recyclerview.adapter = adapter
                binding.recyclerview.setHasFixedSize(true)
            }

            override fun onFailure(call: Call<List<adsModel?>?>, t: Throwable) {
                Toast.makeText(requireContext(), t.message.toString(), Toast.LENGTH_SHORT).show()
            }

        })
    }

4 Answers4

2
java.lang.NullPointerException: null cannot be cast to non-null type kotlin.collections.List<com.crazybot.rewardoomadvertiser.model.adsModel>

You are trying to cast a null to a non-null type which is raised in the below cast:

val adapter: adsAdapter = adsAdapter(obj as List<adsModel>, this@ManageAdsFragment)

The obj is the null and this is true because the API response can be nullable in some cases.

And the non-null type is the first parameter of the adsAdapter constructor where you didn't specify that it's a nullable using the Optional ?:

So, to fix this either:

  1. Make List<adsModel> param of the adsAdapter nullable, and this requires you to replace each instance of the adsList to adsList?:
class adsAdapter(
    private val adsList: List<adsModel>?,
  1. Check if the obj is null before instantiating the adapter:
call?.enqueue(object : Callback<List<adsModel?>?>{
    override fun onResponse(
        call: Call<List<adsModel?>?>,
        response: Response<List<adsModel?>?>
    ) {
        obj = response.body()
        if (obj != null) {
            val adapter: adsAdapter = adsAdapter(obj as List<adsModel>, this@ManageAdsFragment)
            binding.recyclerview.layoutManager = LinearLayoutManager(requireContext())
            binding.recyclerview.adapter = adapter
            binding.recyclerview.setHasFixedSize(true)
        }
    }

    override fun onFailure(call: Call<List<adsModel?>?>, t: Throwable) {
        Toast.makeText(requireContext(), t.message.toString(), Toast.LENGTH_SHORT).show()
    }

})
Zain
  • 37,492
  • 7
  • 60
  • 84
  • after I implemented your method I thought it will work but it didn't then @Tanjim helped me to change a line in adapter class then it work. Thank you so much – Steve Harrington Aug 27 '21 at 13:49
0

Be sure that in the line obj = response.body() you are not getting a null value

franvillacis
  • 199
  • 4
0

Your obj is null at this line:

val adapter: adsAdapter = adsAdapter(obj as List<adsModel>, this@ManageAdsFragment)

Do rather this:

val adapter = adsAdapter(
    obj ? as List<adsModel> : emptyList(), 
    this@ManageAdsFragment
)
aiqency
  • 1,015
  • 1
  • 8
  • 22
0

@zain Answer is correct but I don't think it's enough you have to change a line of code in your adapter class

change this line

override fun getItemCount() = adsList.size

To this

 val adapter: adsAdapter = adsAdapter(obj as List<adsModel>?, this@ManageAdsFragment)
Tanjim ahmed
  • 473
  • 4
  • 15