Home > Net >  How to use the same RecyclerView adapter with Activity and Fragment in Kotlin?
How to use the same RecyclerView adapter with Activity and Fragment in Kotlin?

Time:11-15

I have created an app that works perfectly. I decided to make some changes to my app, that is, use Fragment instead of Activity at some places. This activity has a RecyclerView in it and that is used to load data which is fetched from the Firestore. Everything will remain the same except Fragment will be used instead of Activity.

Now the problem I have is with the recyclerView adapter where it takes context.

open class CargoListAdapter(
    private val context: Context,
    private var list: ArrayList<Cargo>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

When a button is clicked, I have to check the context to take further action accordingly.

            holder.binding.ibDelete.setOnClickListener {

            when (context) {
                is OrderActivity -> {
                    val activity = holder.itemView.context as? OrderActivity

                    activity?.viewSpecialRequest(
                        model.custom_request
                    )
                }

                is MyOrderDetailsActivity -> {
                    val activity = holder.itemView.context as? MyOrderDetailsActivity

                    activity?.viewSpecialRequest(
                        model.custom_request
                    )
                }

                is CargoFragment -> {
                    val activity = holder.itemView.context as? CargoFragment

                    activity?.viewSpecialRequest(
                        model.custom_request

                    )

                }
            }
        }

This is how I am calling from one of the activities.

val cargoListAdapter = CargoListAdapter(this@OrderActivity, mCargoList)

I tried to call from the fragment like below but I can see an error "Incompatible types: CargoFragment and Context" at is CargoFragment -> {

val cargoListAdapter = CargoListAdapter(requireContext(), mCargoList)

CodePudding user response:

you check the context and then convert it to activity or fragment where the adapter was created, and after you call activity/fragment method viewSpecialRequest this is not very correct, if you want to call activity/fragment methods after click on ibDelete you need to add for example an interface.

open class CargoListAdapter(
    private val context: Context,
    private var list: ArrayList<Cargo>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

interface OnItemActionsListener {
        fun onDeleteClicked()
    }

var onItemActionsListener:OnItemActionsListener? =null

 holder.binding.ibDelete.setOnClickListener {
     onItemActionsListener?.onDeleteClicked()
 } 

********* 
 }
}

OrderActivity

adapter = CargoListAdapter(this, arrayListOf())
adapter.onItemActionsListener = object  : CargoListAdapter.OnItemActionsListener {
                    override fun onDeleteClicked() {
                        // TODO logic
                    }
                }

CargoFragment

adapter = CargoListAdapter(requireActivity(), arrayListOf())
adapter.onItemActionsListener = object  : CargoListAdapter.OnItemActionsListener {
                    override fun onDeleteClicked() {
                        // TODO logic
                    }
                }

if you need to do the logic in the adapter, instead of context check, you can use enum.

public enum DeleteCaseEnum {
    NONE, CASE_1, CASE_2, CASE_3
}

open class CargoListAdapter(
    private val context: Context,
    private var list: ArrayList<Cargo>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

var deleteCase:DeleteCaseEnum  = DeleteCaseEnum .NONE

   holder.binding.ibDelete.setOnClickListener {

            when (deleteCase) {
                is DeleteCaseEnum.CASE_1-> {
                 // TODO
                }
              
                is DeleteCaseEnum.CASE_2-> {
                 // TODO
                }
            }

OrderActivity

adapter = CargoListAdapter(this, arrayListOf())
adapter.deleteCase = DeleteCaseEnum.CASE_1

CargoFragment

adapter = CargoListAdapter(requireActivity(), arrayListOf())
adapter.deleteCase = DeleteCaseEnum.CASE_2

CodePudding user response:

Instead of using an interface and accessing function by using Activity or Fragment instance you can use Kotlin higher order functions to make the adapter independent and use it anywhere in the code.

open class CargoListAdapter(
    private val context: Context,
    private var list: ArrayList<Cargo>,
    private val onClickItem:(pos: Int) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

Call onClickItem in ViewHolder on click :

holder.binding.ibDelete.setOnClickListener {
    onClickItem(adapterPosition)
}

In Activity or Fragment :

adapter = CargoListAdapter(context, list){position->
   //receive click here
}

Checkout this gist for complete adapter example : https://github.com/Noddy20/Gists/blob/master/RecyclerViewAdapter-1.kt

  • Related