Как ввести адаптер с рукоятью

У меня есть полный пример recyclerView, теперь я хочу использовать рукоятку для вставки 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)
}

person ccd    schedule 02.09.2020    source источник
comment
Могу я спросить, почему вы хотите это сделать? Вам не нужно вводить все и везде.   -  person Bartek Lipinski    schedule 02.09.2020
comment
Я пытался это сделать, но не знаю, нужно ли это делать.   -  person ccd    schedule 02.09.2020
comment
Сэр @BartekLipinski, это плохая практика - вводить адаптер таким образом или не вводить его вообще?   -  person EL TEGANI MOHAMED HAMAD GABIR    schedule 18.09.2020
comment
@ELTEGANIMOHAMEDHAMMADGABIR, это полностью основано на мнении. Если вы спросите меня, делаю ли я такие инъекции в своем коде, ответ будет отрицательным. Но кто я такой, чтобы рассказывать тебе, как писать собственный код ????   -  person Bartek Lipinski    schedule 18.09.2020
comment
@BartekLipinski, хорошо, я буду следовать твоему подходу. спасибо за вашу скромность   -  person EL TEGANI MOHAMED HAMAD GABIR    schedule 18.09.2020


Ответы (2)


Это то, что вы хотите? Можете ли вы проверить, работает ли это и удовлетворяет ли это ваши потребности.

ПРИМЕЧАНИЕ: я ожидаю, что вы правильно настроили аннотации, поэтому рукоятка была настроена и правильно работает в вашем проекте (например, аннотирование фрагмента ItemListFragment с помощью @AndroidEntryPoint и т. д.)

У меня был такой случай, и я подумал, что вместо того, чтобы использовать обратный вызов в конструкторе, я должен предоставить его через метод установки адаптера.

Для ItemListAdapter мы можем создать свойство типа ItemListOnClickListener и предоставить setOnClickListener метод установки. Вот и все, теперь вы можете использовать onClickListener в ViewHolder (теперь конструктор 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
    }
}
person Ahmed Shendy    schedule 03.09.2020
comment
Спасибо за совет, попробовав рукоять для адаптера, я думаю, что может потребоваться более сложная операция, чем без него. - person ccd; 05.09.2020

Ответ, февраль 2021 г.

Это самый простой ответ.

В классе модуля

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

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

В классе адаптера

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
}

Если у вас все еще есть путаница, вот полный исходный код

person Vikash Parajuli    schedule 10.02.2021
comment
исходный код не работает, существующий ключ api не работает, невозможно создать новый ключ api - person fairy; 14.04.2021
comment
код выглядит чистым и хорошим, можете ли вы проверить свой ключ API или дать образец json - person fairy; 14.04.2021