kotlin.TypeCastException: null cannot be cast to non-null type kotlin.collections.MutableList

落花浮王杯 提交于 2020-08-20 13:23:57

问题


please dont marked as duplicate , as the question is slightly different ---> null cannot be cast to non-null type kotlin.collections.MutableList

Scenerios:-

i have been performing delete cart using retrofit..

  1. if atleast one item is present ,it displays in recyclerview

2.if cart is empty ,it crashes with a above error

here is my adapter code:-

class CartAdapter(context: Context, dataList: MutableList<DataCart?>) :
RecyclerSwipeAdapter<CartAdapter.CustomViewHolder>() { //added RecyclerSwipeAdapter and override
 private   var dataList: MutableList<DataCart>
private val context: Context
 lateinit var  dialog:ProgressDialog
var progressDialog: ProgressDialog? = null


inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val mView: View
   val swipelayout:SwipeLayout
    val productiamge: ImageView
    val productname: TextView
    val productcategory: TextView
    val productprice: TextView
    val quantity:TextView
    val tvDelete:TextView
    init {
        mView = itemView
    productiamge= mView.findViewById(R.id.imagecart)
       productname= mView.findViewById(R.id.imagenamecart)
        productcategory= mView.findViewById(R.id.imagecategory)
     productprice =mView.findViewById(R.id.price)
        quantity=mView.findViewById(R.id.quantity)
        swipelayout=mView.findViewById(R.id.swipe)
        tvDelete=mView.findViewById(R.id.tvDelete)
    }

}

      override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
    val layoutInflater = LayoutInflater.from(parent.context)
    val view: View = layoutInflater.inflate(R.layout.addtocart_item, parent, false)
    return CustomViewHolder(view)
}

override fun getSwipeLayoutResourceId(position: Int): Int {
    return R.id.swipe;

}

override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
  val  progressDialog :ProgressDialog= ProgressDialog(context);

    holder.productname.text = dataList.get(position).product.name ?: null
    holder.productcategory.text = "(" +dataList.get(position).product.product_category +")"

    holder.productprice.text = dataList.get(position).product.cost.toString()

    Glide.with(context).load(dataList.get(position).product.product_images)
        .into(holder.productiamge)
    holder.quantity.text=dataList.get(position).quantity.toString()

    holder.swipelayout.setShowMode(SwipeLayout.ShowMode.PullOut)
    Log.e("checkidd",dataList.get(position).product.id.toString())
    // Drag From Right

    // Drag From Right
    holder.swipelayout.addDrag(
        SwipeLayout.DragEdge.Right,
        holder.swipelayout.findViewById(R.id.bottom_wrapper)
    )
    val id =dataList.get(position).product?.id

        holder.swipelayout.addSwipeListener(object : SwipeListener {
        override fun onClose(layout: SwipeLayout) {            }

        override fun onUpdate(layout: SwipeLayout, leftOffset: Int, topOffset: Int) {
            //you are swiping.
        }

        override fun onStartOpen(layout: SwipeLayout) {}
        override fun onOpen(layout: SwipeLayout) {
        }

        override fun onStartClose(layout: SwipeLayout) {}
        override fun onHandRelease(
            layout: SwipeLayout,
            xvel: Float,
            yvel: Float
        ) {
        }
    })
    holder.swipelayout.getSurfaceView()
        .setOnClickListener(View.OnClickListener {
        })

   holder.tvDelete.setOnClickListener(View.OnClickListener {
    view ->

    val token :String = SharedPrefManager.getInstance(context).user.access_token.toString()
RetrofitClient.instancecart.deletecart(token,id!!)
    .enqueue(object : Callback<DeleteResponse> {
        override fun onFailure(call: Call<DeleteResponse>, t: Throwable) {
        }

        override fun onResponse(
            call: Call<DeleteResponse>,
            response: Response<DeleteResponse>
        ) {
            var res = response

            if (res.body()?.status==200) {
                Toast.makeText(
                    context,
                    res.body()?.message,
                    Toast.LENGTH_LONG
                ).show()
                progress()
                mItemManger.removeShownLayouts(holder.swipelayout)
                notifyItemChanged(position)
                notifyItemRemoved(position)
                dataList?.removeAt(position)
                notifyItemRangeChanged(position, dataList?.size!!)
                mItemManger.closeAllItems()
                progressDialog.show()
            }
            else{
                try {
                    val jObjError =
                        JSONObject(response.errorBody()!!.string())
                    Toast.makeText(
                        context,
                        jObjError.getString("message")+jObjError.getString("user_msg"),
                        Toast.LENGTH_LONG
                    ).show()
                } catch (e: Exception) {
                    Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
                    Log.e("errorrr",e.message)
                }
            }
        }
    })
mItemManger.bindView(holder.itemView, position)
     })
}
override fun getItemCount(): Int {
    return dataList.size
}
fun progress()
{
    progressDialog?.dismiss()
    val intent =
        Intent(context.applicationContext, AddToCart::class.java)
    intent.flags =
        Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
    context.applicationContext.startActivity(intent)
}

    init {
    this.context = context
    this.dataList = dataList 
   }}

here is my activity:

   class AddToCart:AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.add_to_cart)
   val totalamount:TextView=findViewById(R.id.totalamount)
    val token: String =
        SharedPrefManager.getInstance(
            applicationContext
        ).user.access_token.toString()
    RetrofitClient.instancecart.listcart(token).enqueue( object :
        Callback<CartResponse> {
        override fun onFailure(call: Call<CartResponse>, t: Throwable) {
            Toast.makeText(applicationContext,"falied", Toast.LENGTH_LONG).show()
        }

        override fun onResponse(
            call: Call<CartResponse>,
            response: Response<CartResponse>
        ) {
            val res=response
            if (response.isSuccessful) {
                val retro:List<DataCart> = response.body()!!.data
      totalamount.setText(response.body()?.total.toString())

                generateDataList(retro as MutableList<DataCart?>)

            }
        }

    })
}
fun generateDataList( dataList:MutableList<DataCart?>) {
    val recyclerView=findViewById<RecyclerView>(R.id.addtocartrecyleview) as? RecyclerView
    val linear:LinearLayoutManager=
        LinearLayoutManager(applicationContext,LinearLayoutManager.VERTICAL, false)
    recyclerView?.layoutManager=linear
    val adapter = CartAdapter(this@AddToCart,dataList)
    recyclerView?.adapter=adapter
    recyclerView?.addItemDecoration
    (DividerItemDecorator(resources.getDrawable(R.drawable.divider)))
    recyclerView?.setHasFixedSize(true)

    adapter.notifyDataSetChanged()

    if (dataList.isEmpty()) {
        recyclerView?.setVisibility(View.GONE)
        textviewempty.setVisibility(View.VISIBLE)
    } else {
        recyclerView?.setVisibility(View.VISIBLE)
        textviewempty.setVisibility(View.GONE)
    }




  recyclerView?.addOnScrollListener(object :
        RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
            Log.e("RecyclerView", "onScrollStateChanged")
        }

        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
        }
    })
}

override fun onBackPressed() {
    super.onBackPressed()
    val intent = Intent(this, HomeActivity::class.java)
    startActivityForResult(intent, 2)
}

}

i tried this-->by doing some changes-->

1--> var dataList: MutableList<DataCart?>

2--> var dataList: MutableList<>?=null

3--> var dataList: MutableList<>

Error log after doing Mutablelist to Arraylist

kotlin.TypeCastException: null cannot be cast to non-null type java.util.ArrayList<com.example.store.Cart.DataCart>
    at com.example.store.Cart.AddToCart$onCreate$1.onResponse(AddToCart.kt:40)
    at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:70)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:224)
    at android.app.ActivityThread.main(ActivityThread.java:7147)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:536)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)

but nothing seems to be handling null

Please help me


回答1:


Looks like it can be fixed by changing few lines:

Make CartAdapter accept nullable argument dataList, since your api request may return null and passing it would cause NPE.

class CartAdapter(context: Context, dataList: MutableList<DataCart?>?)

Since our dataList is nullable and calling dataList.size might throw NPE we need to make safe call using ?. And if it's null we just return 0, telling recyclerView that there are 0 items.

override fun getItemCount() = datalist?.size ?: 0

Need to make val retro:List<DataCart> nullable, because response.body()?.data may return null. We just convert retro to mutableList using extension function toMutableList(), with safe call operator "?". If retro is null then null value will be passed to CartAdapter, and since our adapter handles null value it will proceed without errors

if (response.isSuccessful) {
                val retro:List<DataCart>? = response.body()?.data
                totalamount.setText(response.body()?.total.toString())
                generateDataList(retro?.toMutableList())
            }

Remove init() function from CartAdapter and add var(actually should be val) before arguments in constructor. init() is redundant here because u r using it to assign values to redundant, duplicate member variables. By adding var(should be val) to constructor arguments they will be assigned values and be available as member variables, right after object construction.


Since dataList is nullable, and we need to determine its size for further logic safe call needs to be used, and if its null return true - empty

 (dataList?.isEmpty() ?: true)

or use

`(dataList.isNullOrEmpty())` 

which is cleaner, and should work too.


NOTE: Personally, i would'nt suggest you to retinitialize Adapter everytime you need to change values. Instead create val items = arrayListOf<DataCart>(). as a member variable and add a setter function for updating it, inside of which you would call notifyDatasetChanged() or other notify methods.




回答2:


Can't find a reason to use MutableList but your issue is incorrect type cast (dataList as MutableList<DataCart>). This is cause null cannot be cast to non-null type. You can simplify code using class CartAdapter(private val context: Context, private val dataList: ArrayList<DataCart?>?) and remove var dataList: MutableList<DataCart?>, private val context: Context and init{}




回答3:


Null check by using the Elvis operator in the part to set in the shopping cart

The first or second method seems to be good



来源:https://stackoverflow.com/questions/63224711/kotlin-typecastexception-null-cannot-be-cast-to-non-null-type-kotlin-collection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!