簡體   English   中英

如何用刀柄注入適配器

[英]How to inject adapter with hilt

我有一個完整的 recyclerView 示例,現在我想使用 hilt 將此示例的 ItemListAdapter 注入到我的 ItemListFragment 中。 但是,如果我還想要刀柄的方式,似乎是無法做到的事情。

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

這是你想要的嗎? 你能檢查一下這是否有效並滿足你的需要嗎?

注意:我希望您能很好地設置注釋,以便在您的項目中正確設置和工作刀柄(例如:使用@AndroidEntryPoint注釋ItemListFragment片段等...)

我遇到過這樣的情況,我認為與其在構造函數中提供回調,不如通過適配器的 setter 方法提供它。

對於ItemListAdapter ,我們可以創建一個ItemListOnClickListener類型的屬性,並提供setOnClickListener setter 方法。 就是這樣,現在您可以在ViewHolder onClickListener現在ItemListAdapter構造函數是一個無參數構造函數,並且Hilt能夠為您的情況提供綁定):

@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(...))
        }
    }
}

對於ItemListFragment ,您無需構建適配器,因為 Hilt 可以為您提供一個。 您所要做的就是通過此適配器的setOnClickListener方法提供一個偵聽器:

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

2021 年 2 月答復

這是最簡單的答案。

在模塊 class 中

@Module
@InstallIn(SingletonComponent::class)
class AppModule {

    @Provides
    @Singleton
    fun provideAdapter(): MyAdapter = MyAdapter()
}

在適配器 class

private var onItemClickListener: ((RestaurantX) -> Unit)? = null
fun setOnItemClickListener(listener: (RestaurantX) -> Unit) {
        onItemClickListener = listener
}

然后把這一行放在view.setOnClckListener里面

onItemClickListener?.let {
   it(restaurantX)
}

在活動/片段中

 @Inject
 lateinit var myAdapter: MyAdapter

然后在一個方法里面

myAdapter.setOnItemClickListener {it->
            //do whatever you like
}

如果您仍然感到困惑,這里是完整的源代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM