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