Android Kotlin:null 不能转换为非 null 类型 com.android.app.ui.category.CategoryAdapter.ViewHolder 想要在 recycl

Posted

技术标签:

【中文标题】Android Kotlin:null 不能转换为非 null 类型 com.android.app.ui.category.CategoryAdapter.ViewHolder 想要在 recycleviewholder 中插入 admob【英文标题】:Android Kotlin : null cannot be cast to non-null type com.android.app.ui.category.CategoryAdapter.ViewHolder want to insert admob in recycleviewholder 【发布时间】:2021-06-29 18:06:06 【问题描述】:

由于对 Kotlin 编程语言的了解有限,我尝试编辑之前正常运行的代码。我的目标是在已经运行良好的 recycleview 数据之间添加 admob 横幅。试了1周以上,没有明显效果,请大家帮忙,让Admob横幅功能在recycleview适配器上正常运行。

这是运行良好的原始 CategoryAdapter.kt

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)
                
            
        
    

然后我添加此代码以在 recycleview.adapter 中插入 admob 横幅

    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")
                
            

        
    

这是我为在 recycleview.adapter 中显示 AdMob 横幅而修改的代码的最终结果

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)
                
            
        
    

但我收到以下错误

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)

我为我的丑陋问题道歉,希望有人可以帮助我。完全陷入僵局超过 1 周,正在寻找在 recycleview.adapter 中显示 admob 横幅的正确方法。

【问题讨论】:

从错误日志中,我假设您提供的 viewType 既不是 1 也不是 2,并且您尝试返回 null。为了防止这些错误,您可以直接从 when 开关返回。如果只有 2 种情况会发生,您可以将第 1 种情况作为一个数字,并将第 2 种情况替换为 else。 【参考方案1】:

在这里,您试图将一个可为空的 var 强制转换为一个非 null,这是不可能的。

return viewHolder as ViewHolder

改为提供默认的 ViewHolder。

return viewHolder?: DefaultViewHolder

请注意,您的 when 语句可能未分配有效的 viewHolder,而 onCreateViewHolder 非常需要一个。

【讨论】:

以上是关于Android Kotlin:null 不能转换为非 null 类型 com.android.app.ui.category.CategoryAdapter.ViewHolder 想要在 recycl的主要内容,如果未能解决你的问题,请参考以下文章

null 不能转换为非 null 类型 kotlin.collections.List - kotlin

kotlin.TypeCastException: null 不能转换为非 null 类型 com.midsizemango.databasekotlin.Note

null 不能强制转换为非 null 类型 kotlin.String NullPointer 异常

致命异常 java.lang.NullPointerException: null 不能转换为非 null 类型 kotlin.String

如何在android上将kotlin转换为java? [复制]

是否可以使用 Android Studio 将 Kotlin 转换为 Java? [复制]