I have a list of items in a RecyclerView that is in a Fragment, and I am trying to make it open an URL by clicking on a certain item. For example, if I click on the first item, it should redirect me to url1, but if I click on the second, it should redirect to url2.
I have seen solutions for recyclerviews in main activity, but those don't seem work in Fragments.
This is DietAdapter.kt
class DietAdapter(val dietList: List<Diet>): RecyclerView.Adapter<DietAdapter.DietViewHolder>(){
inner class DietViewHolder(val itemBinding: ListitemBinding)
:RecyclerView.ViewHolder(itemBinding.root) {
fun bindItem(diet:Diet){
itemBinding.titleImage.setImageResource(diet.titleImage)
itemBinding.tvHeading.text = diet.heading
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DietViewHolder {
return DietViewHolder(ListitemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: DietViewHolder, position: Int) {
val diet = dietList[position]
holder.bindItem(diet)
holder.itemBinding.rowList.setOnClickListener(View.OnClickListener {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("<add url here>"))
requireContext().startActivity(browserIntent) //<--here the requireContext throws "no value passed for parameter 'provider' "
})
}
override fun getItemCount(): Int {
return dietList.size
}
}
Add a Context property to your constructor:
class DietAdapter(val context: Context, val dietList: List<Diet>) //...
and when you create the adapter in your fragment, pass requireContext()
as the parameter for context
. Now you can use context.startActivity()
inside your adapter's click listener(s).
Your adapter should not be internally responsible for navigation. That is a job for the higher level object, the Fragment. Trying to have the adapter reach into the Fragment to do things that a Fragment should do makes your code more convoluted. Instead, the adapter should expose a listener property (changes from your code are commented):
class DietAdapter(
val dietList: List<Diet>,
var onItemClick: (Diet)->Unit = {} // Added this
): RecyclerView.Adapter<DietAdapter.DietViewHolder>(){
inner class DietViewHolder(val itemBinding: ListitemBinding)
:RecyclerView.ViewHolder(itemBinding.root) {
fun bindItem(diet:Diet){
itemBinding.titleImage.setImageResource(diet.titleImage)
itemBinding.tvHeading.text = diet.heading
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DietViewHolder {
return DietViewHolder(ListitemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: DietViewHolder, position: Int) {
val diet = dietList[position]
holder.bindItem(diet)
// Changed this:
holder.itemBinding.rowList.setOnClickListener { onItemClick(diet) }
}
override fun getItemCount(): Int {
return dietList.size
}
}
Then, the fragment is where you decide what to do with clicked items:
val dietAdapter = DietAdapter(theDataList) { diet ->
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("<add url here>"))
requireContext().startActivity(browserIntent)
}
binding.myRecyclerView.adapter = dietAdapter