1

I'm performing a retrofit call inside an adapter..i have successfully implemented and also it is giving me the desired output but is it a good practice to perform this under adapter?????

my app is --> product selling app-->in my cart-->im displaying the product list which user wants to buy-->for this required an adapter-->there im performing a swipe to delete function -->performing retrofit call on delete(holder.delete.setonclicklistener {...}) button

my code is-->

        holder.tvDelete.setOnClickListener(View.OnClickListener { view ->
        progressDialog.show()

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

                    Log.d("res", "" + t)


                }

                override fun onResponse(
                    call: Call<DeleteResponse>,
                    response: Response<DeleteResponse>
                ) {
                    var res = response
                    progressDialog.dismiss()
                    (context as Activity).finish()

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


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

    })

the above code is working

i have also gone through this --> passing data from on click function of my recycler adaptor

this link i performed but in activity i wont be getting access to this code in activity

    mItemManger.removeShownLayouts(holder.swipelayout)
                        notifyItemChanged(position)
                        notifyItemRemoved(position)
                        dataList?.removeAt(position)
                        notifyItemRangeChanged(position, dataList?.size!!)
                        mItemManger.closeAllItems()

need clarification on this

need help thanks

Edit:-- i followed the above link here is my code

interface

interface OnItemClick {
fun onItemClicked(position: Int)

 }

activity

class AddToCart:BaseClassActivity(), OnItemClick{
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.add_to_cart)
    getWindow().setExitTransition(null)
    getWindow().setEnterTransition(null)
    var mActionBarToolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbartable);
    setSupportActionBar(mActionBarToolbar);
    // add back arrow to toolbar
  setEnabledTitle()

    mActionBarToolbar.setNavigationOnClickListener(View.OnClickListener {
        onBackPressed()
    })
    placeorder.setOnClickListener {
        val intent:Intent=Intent(applicationContext, AddressActivity::class.java)
        startActivity(intent)
    }
   loadCart()
  }

   fun loadCart(){

  val model = ViewModelProvider(this)[CartViewModel::class.java]

  model.CartList?.observe(this, object : Observer<CartResponse> {
      override fun onChanged(t: CartResponse?) {

          generateDataList(t?.data?.toMutableList())
          totalamount.setText(t?.total.toString())
      }
  })
  }

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


    adapter.notifyDataSetChanged()
     adapter.setItemClick(this)
    if (dataList?.isEmpty() ?: true) {
        recyclerView?.setVisibility(View.GONE)
        totalamount.setVisibility(View.GONE)
        fl_footer.setVisibility(View.GONE)
        placeorder.setVisibility(View.GONE)
        emptytext.setVisibility(View.VISIBLE)
    } else {
        recyclerView?.setVisibility(View.VISIBLE)
        totalamount.setVisibility(View.VISIBLE)
        fl_footer.setVisibility(View.VISIBLE)
        placeorder.setVisibility(View.VISIBLE)
        emptytext.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)
      startActivity(intent)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        android.R.id.home -> {
            NavUtils.navigateUpFromSameTask(this)

            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

override fun onResume() {
    super.onResume()
   loadCart()
}


override fun onItemClicked(position: Int) {

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

                Log.d("res", "" + t)


            }

            override fun onResponse(
                call: Call<DeleteResponse>,
                response: Response<DeleteResponse>
            ) {
                var res = response
                (applicationContext as Activity).finish()

                if (res.body()?.status == 200) {
                    Toast.makeText(
                        applicationContext,
                        res.body()?.message,
                        Toast.LENGTH_LONG
                    ).show()
                    val intent =
                        Intent(applicationContext, AddToCart::class.java)
                    intent.flags =
                        Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
                    applicationContext.startActivity(intent)
                    (applicationContext as Activity?)!!.overridePendingTransition(0, 0)


                } else {
                    try {
                        val jObjError =
                            JSONObject(response.errorBody()!!.string())
                        Toast.makeText(
                            applicationContext,
                            jObjError.getString("message") + jObjError.getString("user_msg"),
                            Toast.LENGTH_LONG
                        ).show()
                    } catch (e: Exception) {
                        Toast.makeText(applicationContext, e.message, Toast.LENGTH_LONG).show()
                        Log.e("errorrr", e.message)
                    }
                }
            }
        })

}
   }

adapter:--

class CartAdapter(private val context: Context, private val dataList: MutableList<DataCart?>?) :
RecyclerSwipeAdapter<CartAdapter.CustomViewHolder>() , AdapterView.OnItemSelectedListener{ //added RecyclerSwipeAdapter and override
private var itemClick: OnItemClick? = null

inner class CustomViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
    View.OnClickListener {
    val mView: View
  val swipelayout:SwipeLayout
    val productiamge: ImageView
    val productname: TextView
    val productcategory: TextView
    val productprice: TextView
    val tvDelete:TextView
    val spin:Spinner
    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)
        swipelayout=mView.findViewById(R.id.swipe)
        tvDelete=mView.findViewById(R.id.tvDelete)
         spin = mView.findViewById(R.id.spinner) as Spinner
        tvDelete.setClickable(true);
        tvDelete.setOnClickListener(this);

    }

    override fun onClick(v: View?) {
        if (itemClick != null) {
            itemClick!!.onItemClicked(getPosition());
        }
    }


}

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.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.tvDelete.setOnClickListener(View.OnClickListener { view ->
        mItemManger.removeShownLayouts(holder.swipelayout)
        notifyItemChanged(position)
        notifyItemRemoved(position)
        dataList?.removeAt(position)
        notifyItemRangeChanged(position, dataList?.size!!)
        mItemManger.closeAllItems()
    })
    mItemManger.bindView(holder.itemView, position)


}
    override fun getItemCount() = dataList?.size ?: 0

override fun onNothingSelected(p0: AdapterView<*>?) {
    TODO("Not yet implemented")
}

override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {

}
fun getItemClick(): OnItemClick? {
    return itemClick
}

fun setItemClick(itemClick: OnItemClick?) {
    this.itemClick = itemClick
}

}

but im not getting an desired output help me

android dev
  • 200
  • 5
  • 18
  • "is it a good practice to perform this under adapter??" - The theory says no because the adapter + viewholder only must be show the data and set the listeners, that´s all (UI module). The responsibility to implement the network logic is of a data network class, injecting your retrofit interface, and if you need another data from another datasource as SharedPreferences, your Repository could prepare the necessary data to do the call (Data Module). And if you need business logic and you want to implement a clean architecture, then you could to create a Domain Module (Use Cases + Entities) – Manuel Mato Oct 23 '20 at 07:05
  • @ManuelMato can you see the edited code – android dev Oct 23 '20 at 07:49
  • 1
    One more step, and you'll move what you're doing into the ViewModel, that's what you are looking to accomplish :) – EpicPandaForce Oct 23 '20 at 16:28
  • @EpicPandaForce that I got it viewmodel... But how do I pass the click of adapter? That delete button? And I can't get an instance of viewmodel in adapter? That I have to do it in activity ofcourse ?how do I access that holder.delete in activity... Really confused ☹️ Need help – android dev Oct 24 '20 at 20:19
  • 1
    You can technically pass the ViewModel to the Adapter, but I'd rather define an interface in the Adapter for the item click, then expose that to the Fragment, and the Fragment would call over to the VM. – EpicPandaForce Oct 24 '20 at 23:35
  • 1
    wow it worked @EpicPandaForce thanks a lot..you always help me :) :) – android dev Oct 26 '20 at 07:44
  • @EpicPandaForce need help in spinner selection using viewmodel --> https://stackoverflow.com/questions/64537639/spinner-value-using-retrofit-and-viewmodel – android dev Oct 26 '20 at 13:02
  • You should add the working code as an answer – EpicPandaForce Oct 26 '20 at 13:47
  • @EpicPandaForce okay i will do it :) – android dev Oct 26 '20 at 13:49
  • hi @EpicPandaForce could u help me out here ->https://stackoverflow.com/questions/76786965/facing-issue-while-validating-amongst-the-edittexts-in-recyclerview – android dev Jul 28 '23 at 13:45

2 Answers2

2

with the help of user EpicPandaForce i got an answer to problem question

Interface::----

interface OnItemClick {
fun DeleteItem(position: Int, id:Int)
}

Adapter::----

    private var itemClick: OnItemClick? = null
     .
    .
     .
      holder.tvDelete.setOnClickListener(View.OnClickListener { view ->
        mItemManger.removeShownLayouts(holder.swipelayout)
        notifyItemChanged(position)
        notifyItemRemoved(position)
        dataList?.removeAt(position)
        itemClick?.DeleteItem(position,id!!.toInt())

        notifyItemRangeChanged(position, dataList?.size!!)
        mItemManger.closeAllItems()
    })
    mItemManger.bindView(holder.itemView, position)


    }
    .
    .
     .
     
fun setItemClick(itemClick: OnItemClick?) {
    this.itemClick = itemClick
}

Activity::----

class AddToCart:BaseClassActivity(), OnItemClick{
 .
 .
  .
   onCreate(){
            adapter.setItemClick(this);
       .
       .
       .
       }
         override fun DeleteItem(position: Int, id:Int) {
    progressDialog?.show()
        viewModel.product_id.value =id.toString()
    viewModel.loaddelete()
    viewModel.Results.observe(this) { result ->
        when (result) {
            CartViewModel.Result.Missing -> {
                Toast.makeText(
                    applicationContext, "product is missing", Toast.LENGTH_LONG
                ).show()

            }


            CartViewModel.Result.Success -> {
                finish()
                val intent =
                    Intent(applicationContext, AddToCart::class.java)
                intent.flags =
                    Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
                startActivity(intent)
                overridePendingTransition(0, 0)                }
            else ->
            {
                Toast.makeText(applicationContext,"hello",Toast.LENGTH_LONG).show()
            }
        }
    }



}

Viewmodel::--------

fun loaddelete(){
    val id = product_id.value!!.toString().trim()

    val token: String = SharedPrefManager.getInstance(getApplication()).user.access_token.toString()
    RetrofitClient.instance.deletecart(token, id)
        .enqueue(object : Callback<DeleteResponse> {
            override fun onFailure(call: Call<DeleteResponse>, t: Throwable) {
                loginResultEmitter.emit(CartViewModel.Result.NetworkFailure)

                Log.d("res", "" + t)


            }

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


                if (res.body()?.status == 200) {
                    Toast.makeText(
                        getApplication(),
                        res.body()?.message,
                        Toast.LENGTH_LONG


                    ).show()


                    loginResultEmitter.emit(CartViewModel.Result.Success)



                } else {
                    try {
                        val jObjError =
                            JSONObject(response.errorBody()!!.string())
                        Toast.makeText(
                            getApplication(),
                            jObjError.getString("message") + jObjError.getString("user_msg"),
                            Toast.LENGTH_LONG
                        ).show()
                    } catch (e: Exception) {
                        Toast.makeText(getApplication(), e.message, Toast.LENGTH_LONG).show()
                        Log.e("errorrr", e.message)
                    }
                }
            }
        })




}
android dev
  • 200
  • 5
  • 18
0

This is not a good practice to make API calls in adapter. You can create callbacks from adapter to activity and should call this API code in activity itself. If you need some references from the adapter then you can create methods in adapter and call these methods in activity by creating adapter's object.

Priyanka
  • 1,791
  • 1
  • 7
  • 12
  • i have performed this --> https://stackoverflow.com/a/32323801/14046751 but im not getting access of this code in my activity `mItemManger.removeShownLayouts(holder.swipelayout) notifyItemChanged(position) notifyItemRemoved(position) dataList?.removeAt(position) notifyItemRangeChanged(position, dataList?.size!!) mItemManger.closeAllItems()` – android dev Oct 23 '20 at 07:02
  • You need to move this code to adapter's method and call that method in class. – Priyanka Oct 23 '20 at 07:04
  • im getting error on this line adapter.setItemClick(this); red at setItemClick – android dev Oct 23 '20 at 07:11
  • This will be populating error to, check what it is saying. I guess you have not implemented callback properly. or you can share your code – Priyanka Oct 23 '20 at 07:14
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/223505/discussion-between-apj123-and-priyanka-rajput). – android dev Oct 23 '20 at 07:42
  • You need to add adapter.setItemClick(AddToCart.this) – Priyanka Oct 23 '20 at 08:20
  • Are you still facing issue? You need to give reference of class as you are in the recyclerview's listener. – Priyanka Oct 23 '20 at 08:24
  • can you come in discussion? – android dev Oct 23 '20 at 08:31