Search code examples
androidkotlinandroid-recyclerviewadmobandroid-viewholder

Android Kotlin : null cannot be cast to non-null type com.android.app.ui.category.CategoryAdapter.ViewHolder want to insert admob in recycleviewholder


with limited understanding of the Kotlin programming language, I tried editing the code that was previously running normally. my goal is to add admob banner between the recycleview data that is already running well. I have tried it for 1 week or more and there have been no significant results, please help so that the Admob banner function can run properly on the recycleview adapter.

This is original CategoryAdapter.kt which is running well

package com.android.app.ui.category

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import coil.load
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdView
import com.android.app.R
import com.android.app.data.entities.Category
import com.android.app.data.type.CategoryType
import com.android.app.databinding.ItemCategoryBinding
import com.android.app.listener.PositionListener

class CategoryAdapter(private val list: List<Category>, private val listener: PositionListener) :
    RecyclerView.Adapter<CategoryAdapter.ViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding =
            ItemCategoryBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(list[position])

    override fun getItemCount(): Int = list.size

    inner class ViewHolder(private val binding: ItemCategoryBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(category: Category) {
            with(binding) {
                ivCategory.load(
                    ContextCompat.getDrawable(
                        binding.root.context, when (category.id - 1) {
                            CategoryType.ART_CULTURE.ordinal -> R.drawable.ic_art_culture
                            CategoryType.GEOGRAPHY.ordinal -> R.drawable.ic_geography
                            CategoryType.MUSIC.ordinal -> R.drawable.ic_music
                            CategoryType.ECONOMY.ordinal -> R.drawable.ic_economy
                            CategoryType.HISTORY.ordinal -> R.drawable.ic_history
                            CategoryType.NATURE.ordinal -> R.drawable.ic_nature
                            CategoryType.FILM_TV.ordinal -> R.drawable.ic_film_tv
                            CategoryType.INFORMATICS.ordinal -> R.drawable.ic_informatics
                            CategoryType.FOOD_AND_DRINK.ordinal -> R.drawable.ic_food_and_drink
                            CategoryType.LANGUAGE.ordinal -> R.drawable.ic_language
                            CategoryType.SCIENCE.ordinal -> R.drawable.ic_science
                            CategoryType.GENERAL.ordinal -> R.drawable.ic_general
                            CategoryType.LITERATURE.ordinal -> R.drawable.ic_literature
                            CategoryType.SPORTS.ordinal -> R.drawable.ic_sports
                            else -> R.drawable.ic_politics
                        }
                    )
                )
                tvCategory.text = category.name
                itemView.setOnClickListener {
                    listener.onItemClicked(category)
                }
            }
        }
    }
}

then I add this code to insert admob banner inside recycleview.adapter

    var viewHolder: RecyclerView.ViewHolder? = null
            val inflater = LayoutInflater.from(parent.context)
            when (viewType) {
                1 -> {
                    val v = inflater.inflate(R.layout.item_category, parent, false)
                    viewHolder = ViewHolder(binding = ItemCategoryBinding.bind(v))
                }
                2-> {
                    val v = inflater.inflate(R.layout.item_list_admob, parent, false)
                    viewHolder = AdmobViewHolder(v)
                }
            }
            return viewHolder as ViewHolder
}

//show Admob Banner in list
    class AdmobViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        var mAdView: AdView = view.findViewById<View>(R.id.adView) as AdView
        init {
            mAdView.visibility = View.GONE
            mAdView.loadAd(AdRequest.Builder().build())
            mAdView.adListener = object : AdListener() {
                override fun onAdLoaded() {
                    super.onAdLoaded()
                    mAdView.visibility = View.VISIBLE
                    Log.i("LOG","Banner List Loaded")
                }
                override fun onAdFailedToLoad(errorCode : Int) {
                    Log.i("LOG","Banner List Failed to load")
                }
            }

        }
    }

This is the final result of the code that I modified to display the AdMob banner in recycleview.adapter

package com.android.app.ui.category

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import coil.load
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdView
import com.android.app.R
import com.android.app.data.entities.Category
import com.android.app.data.type.CategoryType
import com.android.app.databinding.ItemCategoryBinding
import com.android.app.listener.PositionListener

class CategoryAdapter(private val list: List<Category>, private val listener: PositionListener) :
    RecyclerView.Adapter<CategoryAdapter.ViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {

        var viewHolder: RecyclerView.ViewHolder? = null
        val inflater = LayoutInflater.from(parent.context)
        when (viewType) {
            1 -> {
                val v = inflater.inflate(R.layout.item_category, parent, false)
                viewHolder = ViewHolder(binding = ItemCategoryBinding.bind(v))
            }
            2-> {
                val v = inflater.inflate(R.layout.item_list_admob, parent, false)
                viewHolder = AdmobViewHolder(v)
            }
        }
        return viewHolder as ViewHolder

//        val binding =
//            ItemCategoryBinding.inflate(LayoutInflater.from(parent.context), parent, false)
//        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(list[position])

    override fun getItemCount(): Int = list.size

    //show Admob Banner in list
    class AdmobViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        var mAdView: AdView = view.findViewById<View>(R.id.adView) as AdView
        init {
            mAdView.visibility = View.GONE
            mAdView.loadAd(AdRequest.Builder().build())
            mAdView.adListener = object : AdListener() {
                override fun onAdLoaded() {
                    super.onAdLoaded()
                    mAdView.visibility = View.VISIBLE
                    Log.i("LOG","Banner List Loaded")
                }
                override fun onAdFailedToLoad(errorCode : Int) {
                    Log.i("LOG","Banner List Failed to load")
                }
            }

        }
    }

    inner class ViewHolder(private val binding: ItemCategoryBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(category: Category) {
            with(binding) {
                ivCategory.load(
                    ContextCompat.getDrawable(
                        binding.root.context, when (category.id - 1) {
                            CategoryType.ART_CULTURE.ordinal -> R.drawable.ic_art_culture
                            CategoryType.GEOGRAPHY.ordinal -> R.drawable.ic_geography
                            CategoryType.MUSIC.ordinal -> R.drawable.ic_music
                            CategoryType.ECONOMY.ordinal -> R.drawable.ic_economy
                            CategoryType.HISTORY.ordinal -> R.drawable.ic_history
                            CategoryType.NATURE.ordinal -> R.drawable.ic_nature
                            CategoryType.FILM_TV.ordinal -> R.drawable.ic_film_tv
                            CategoryType.INFORMATICS.ordinal -> R.drawable.ic_informatics
                            CategoryType.FOOD_AND_DRINK.ordinal -> R.drawable.ic_food_and_drink
                            CategoryType.LANGUAGE.ordinal -> R.drawable.ic_language
                            CategoryType.SCIENCE.ordinal -> R.drawable.ic_science
                            CategoryType.GENERAL.ordinal -> R.drawable.ic_general
                            CategoryType.LITERATURE.ordinal -> R.drawable.ic_literature
                            CategoryType.SPORTS.ordinal -> R.drawable.ic_sports
                            else -> R.drawable.ic_politics
                        }
                    )
                )
                tvCategory.text = category.name
                itemView.setOnClickListener {
                    listener.onItemClicked(category)
                }
            }
        }
    }
}

but I get the following error

2021-04-03 06:25:47.712 21532-21532/com.android.app E/RecyclerView: No adapter attached; skipping layout
2021-04-03 06:25:47.873 21532-21532/com.android.app E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.android.app, PID: 21532
    java.lang.NullPointerException: null cannot be cast to non-null type com.android.app.ui.category.CategoryAdapter.ViewHolder
        at com.android.app.ui.category.CategoryAdapter.onCreateViewHolder(CategoryAdapter.kt:35)
        at com.android.app.ui.category.CategoryAdapter.onCreateViewHolder(CategoryAdapter.kt:19)
        at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7078)
        at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
        at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
        at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
        at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:561)
        at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
        at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
        at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:170)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
        at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
        at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
        at android.view.View.layout(View.java:22160)
        at android.view.ViewGroup.layout(ViewGroup.java:6402)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1818)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1584)
        at android.view.View.layout(View.java:22160)
        at android.view.ViewGroup.layout(ViewGroup.java:6402)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:22160)
        at android.view.ViewGroup.layout(ViewGroup.java:6402)
        at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:530)
        at android.view.View.layout(View.java:22160)
        at android.view.ViewGroup.layout(ViewGroup.java:6402)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at android.view.View.layout(View.java:22160)
        at android.view.ViewGroup.layout(ViewGroup.java:6402)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
        at android.view.View.layout(View.java:22160)
        at android.view.ViewGroup.layout(ViewGroup.java:6402)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
        at com.android.internal.policy.DecorView.onLayout(DecorView.java:810)
        at android.view.View.layout(View.java:22160)
        at android.view.ViewGroup.layout(ViewGroup.java:6402)
        at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3330)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2826)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1901)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8066)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1041)
        at android.view.Choreographer.doCallbacks(Choreographer.java:860)
        at android.view.Choreographer.doFrame(Choreographer.java:785)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1026)
        at android.os.Handler.handleCallback(Handler.java:914)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:225)
        at android.app.ActivityThread.main(ActivityThread.java:7563)

I apologize for my ugly question, hope someone can help me. totally deadlocked for more than 1 week looking for the right way out to display the admob banner in recycleview.adapter.


Solution

  • Here you are trying to cast a nullable var to a non null which is not possible.

    return viewHolder as ViewHolder
    

    Provide a default ViewHolder instead.

    return viewHolder?: DefaultViewHolder
    

    Notice that your when statement may not assign a valid viewHolder and onCreateViewHolder badly needs one.