如何防止 android 应用程序因 recyclerview 中的空列表而崩溃?
how to prevent android app crashing because of empty list on recycler view?
这是我的适配器 class。当我打开回收器视图时,如果列表为空应用程序崩溃,否则应用程序 运行 顺利。我想我必须对清单做点什么。我的意思是,如果它为空,请做一些可以防止应用程序崩溃的事情。有人可以帮我吗?
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.onResponse(ManageAdsFragment.kt:58)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall.lambda$onResponse[=12=]$DefaultCallAdapterFactory$ExecutorCallbackCall(DefaultCallAdapterFactory.java:89)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$$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 中的功能(我在其中获取回收站视图的数据),最后我使用改造从 rest 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()
}
})
}
确保在行 obj = response.body()
中您没有得到空值
您的 obj
在这一行为空:
val adapter: adsAdapter = adsAdapter(obj as List<adsModel>, this@ManageAdsFragment)
最好这样做:
val adapter = adsAdapter(
obj ? as List<adsModel> : emptyList(),
this@ManageAdsFragment
)
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<adsModel>, this@ManageAdsFragment)
obj
是 null
,这是真的,因为 API 响应在某些情况下可以为 null。
并且非 null 类型是 adsAdapter
构造函数的第一个参数,您没有使用 Optional ?
:
指定它可以为空
因此,要解决此问题:
- 使
adsAdapter
的 List<adsModel>
参数可为空,这需要您将 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()
}
})
@zain 答案是正确的,但我认为您必须更改适配器中的一行代码还不够 class
更改此行
override fun getItemCount() = adsList.size
对此
val adapter: adsAdapter = adsAdapter(obj as List<adsModel>?, this@ManageAdsFragment)
这是我的适配器 class。当我打开回收器视图时,如果列表为空应用程序崩溃,否则应用程序 运行 顺利。我想我必须对清单做点什么。我的意思是,如果它为空,请做一些可以防止应用程序崩溃的事情。有人可以帮我吗?
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.onResponse(ManageAdsFragment.kt:58)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall.lambda$onResponse[=12=]$DefaultCallAdapterFactory$ExecutorCallbackCall(DefaultCallAdapterFactory.java:89)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$$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 中的功能(我在其中获取回收站视图的数据),最后我使用改造从 rest 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()
}
})
}
确保在行 obj = response.body()
中您没有得到空值
您的 obj
在这一行为空:
val adapter: adsAdapter = adsAdapter(obj as List<adsModel>, this@ManageAdsFragment)
最好这样做:
val adapter = adsAdapter(
obj ? as List<adsModel> : emptyList(),
this@ManageAdsFragment
)
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<adsModel>, this@ManageAdsFragment)
obj
是 null
,这是真的,因为 API 响应在某些情况下可以为 null。
并且非 null 类型是 adsAdapter
构造函数的第一个参数,您没有使用 Optional ?
:
因此,要解决此问题:
- 使
adsAdapter
的List<adsModel>
参数可为空,这需要您将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()
}
})
@zain 答案是正确的,但我认为您必须更改适配器中的一行代码还不够 class
更改此行
override fun getItemCount() = adsList.size
对此
val adapter: adsAdapter = adsAdapter(obj as List<adsModel>?, this@ManageAdsFragment)