如何防止android应用程序由于recyclerview中的空列表而崩溃? [复制]

Posted

技术标签:

【中文标题】如何防止android应用程序由于recyclerview中的空列表而崩溃? [复制]【英文标题】:how to prevent android app crashing because of empty list on recycler view? [duplicate] 【发布时间】:2021-10-26 23:36:30 【问题描述】:

这是我的适配器类。当我打开回收站视图时,如果列表为空应用程序崩溃,否则应用程序运行顺利。我想我必须对清单做点什么。我的意思是,如果它为空,请做一些可以防止应用程序崩溃的事情。有人可以帮帮我吗?

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)
    



这里是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)

ManageAdsFragment 中的函数(我在其中获取回收站视图的数据),最后我使用改造从休息 API 获取数据。当我使用带有回收器视图的 firebase 时,我没有收到此类错误

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

        )
    

【问题讨论】:

你能发布崩溃异常堆栈跟踪吗? 我编辑并更新了问题,请帮帮我 @RyanM 遇到同样的情况,但这个答案对我没有帮助,谢谢你问我得到了答案 【参考方案1】:
java.lang.NullPointerException: null cannot be cast to non-null type kotlin.collections.List<com.crazybot.rewardoomadvertiser.model.adsModel>

您正在尝试将 null 强制转换为在以下强制转换中引发的非 null 类型:

val adapter: adsAdapter = adsAdapter(obj as List&lt;adsModel&gt;, this@ManageAdsFragment)

objnull,这是真的,因为 API 响应在某些情况下可以为空。

非空类型是adsAdapter 构造函数的第一个参数,您没有使用可选? 指定它是可空的:

所以,要解决这个问题:

    使adsAdapterList&lt;adsModel&gt; 参数可以为空,这需要您将adsList 的每个实例替换为adsList?
class adsAdapter(
    private val adsList: List<adsModel>?,
    在实例化适配器之前检查obj 是否为空:
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()
    

)

【讨论】:

在我实现了你的方法之后,我认为它会起作用,但它没有然后@Tanjim 帮助我更改适配器类中的一行然后它起作用。非常感谢【参考方案2】:

@zain 答案是正确的,但我认为您必须更改适配器类中的一行代码是不够的

改变这一行

override fun getItemCount() = adsList.size

到这里

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

【讨论】:

【参考方案3】:

确保在obj = response.body() 行中您没有得到空值

【讨论】:

【参考方案4】:

您的obj 在此行为空:

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

不如这样做:

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

【讨论】:

以上是关于如何防止android应用程序由于recyclerview中的空列表而崩溃? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何防止android应用程序由于recyclerview中的空列表而崩溃? [复制]

Android 防止OOM优化

如何使用 youtube data api v3 中的 nextPageToken 在 android recycler 视图中加载更多视频

在Recycler视图上添加图像视图时,Android导航抽屉动画滞后/减速

我想使用 GeoFire 在 android 中填充 Firebase Recycler View

如何从android studio中的recycler视图将数据添加到SQLite数据库中