I have a complete recyclerView example, now I want to use hilt inject the ItemListAdapter of this example to my ItemListFragment. But it seems something that can not be done if I still want the way of hilt.
class ItemListFragment : Fragment() {
private val viewModel: ItemListViewModel by viewModels()
private var adapter: ItemListAdapter? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentItemListBinding.inflate(inflater)
binding.lifecycleOwner = this
binding.viewModel = viewModel
adapter =
ItemListAdapter(
ItemListOnClickListener { itemId ->
viewModel.onItemClicked(itemId)
})
binding.itemList.adapter = adapter
return binding.root
}
}
class ItemListAdapter(private val onClickListener: ItemListOnClickListener):
ListAdapter<Item, ItemListAdapter.ViewHolder>(
ItemListDiffCallback()
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
ListItemBinding.inflate(LayoutInflater.from(parent.context))
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item)
}
class ViewHolder constructor(private val binding: ListItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: Item) {
binding.item = item
binding.executePendingBindings()
}
}
}
class ItemListDiffCallback : DiffUtil.ItemCallback<Item>() {
override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem.id == newItem.id
}
}
class ItemListOnClickListener(val clickListener: (itemID: String) -> Unit) {
fun onClick(itemID: String) = clickListener(itemID)
}
Is this what you want? Can you check if this works and satisfies your need.
NOTE : I expect that you did setup annotations well so hilt was setup and works correctly in your project (ex: annotating ItemListFragment
fragment with @AndroidEntryPoint
, etc...)
I had such case, and I thought rather than feeding the callback in the constructor, I should provide it through a setter method of the adapter.
For ItemListAdapter
, we can make a property of type ItemListOnClickListener
, and provide setOnClickListener
setter method. That's it, now you can make use of onClickListener
in ViewHolder
(Now ItemListAdapter
constructor is a no-arg one, and Hilt is able to provide a binding for it for your case):
@Singleton
class ItemListAdapter @Inject constructor():
ListAdapter<Item, ItemListAdapter.ViewHolder>(ItemListDiffCallback()) {
private var onClickListener: ItemListOnClickListener? = null
...
fun setOnClickListener(onClickListener: ItemListOnClickListener) {
this.onClickListener = onClickListener;
}
inner class ViewHolder constructor(private val binding: ListItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: Item) {
binding.item = item
binding.executePendingBindings()
// Use `onClickListener` when binding `OnClickListener` callback
binding.view.setOnClickListener(v -> onClickListener?.onClick(...))
}
}
}
For ItemListFragment
, you don't need to construct an adapter, because Hilt will be able to provide you with one. All you have to do is provide a listener through setOnClickListener
method of this adapter:
@AndroidEntryPoint
class ItemListFragment: Fragment() {
@Inject
var adapter: ItemListAdapter? = null
private val viewModel: ItemListViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentItemListBinding.inflate(inflater)
...
adapter?.setOnClickListener(
ItemListOnClickListener {
itemId -> viewModel.onItemClicked(itemId)
}
)
binding.itemList.adapter = adapter
return binding.root
}
}
Answer Feb 2021
This is the easiest answer.
In Module class
@Module
@InstallIn(SingletonComponent::class)
class AppModule {
@Provides
@Singleton
fun provideAdapter(): MyAdapter = MyAdapter()
}
In Adapter class
private var onItemClickListener: ((RestaurantX) -> Unit)? = null
fun setOnItemClickListener(listener: (RestaurantX) -> Unit) {
onItemClickListener = listener
}
Then put this line inside view.setOnClckListener
onItemClickListener?.let {
it(restaurantX)
}
In Activity/Fragment
@Inject
lateinit var myAdapter: MyAdapter
And then inside a method
myAdapter.setOnItemClickListener {it->
//do whatever you like
}
If you still have confussion here is full source code
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.