1

我在这里关注这篇文章。一切运行良好,但现在我想为每个项目实现 onclicklistener。

这是我的代码:

SongViewModelAdapter.kt

    class SongViewModelAdapter(private val onSelect: ((ViewModelLyric?) -> Unit)?) : PagingDataAdapter<ViewModelLyric,
        SongViewModelAdapter.SongViewHolder>(Companion) {

    val TAG = "SongViewModelAdapter"

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        val dataBinding = LyricDataBinding.inflate(
            layoutInflater,
            parent,
            false
        )
        return SongViewHolder(dataBinding)
    }

    override fun onBindViewHolder(holder: SongViewHolder, position: Int) {
        val lyric = getItem(position) ?: return
        holder.bindLyric(lyric, onSelect)
    }

    companion object : DiffUtil.ItemCallback<ViewModelLyric>() {
        override fun areItemsTheSame(oldItem: ViewModelLyric, newItem: ViewModelLyric): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: ViewModelLyric, newItem: ViewModelLyric): Boolean {
            return oldItem == newItem
        }
    }

    inner class SongViewHolder(
        private val dataBinding: LyricDataBinding
    ) : RecyclerView.ViewHolder(dataBinding.root) {
        fun bindLyric(lyric: ViewModelLyric, onSelect: ((ViewModelLyric?) -> Unit)?) {
            dataBinding.itemTitle.text = lyric.title
            dataBinding.itemArtist.text = lyric.artist

            dataBinding.root.setOnClickListener {
                onSelect?.let { it1 -> it1(lyric) }
            }
        }
    }
}

HomeFragment.kt

    @AndroidEntryPoint
class HomeFragment : Fragment() {

    val TAG = "HomeFragment"

    private lateinit var binding : FragmentHomeBinding
    private val viewModel by viewModels<HomeFragmentViewModel>()
    private var adapter = SongViewModelAdapter(null)

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = DataBindingUtil.inflate(
            inflater, R.layout.fragment_home, container, false)
        binding.productsRecyclerView.adapter = SongViewModelAdapter(::onSelect)
        return binding.root
    }

    private fun onSelect(viewModelLyric: ViewModelLyric?) {
            val id = viewModelLyric?.id

            val bundle = bundleOf("id" to id)

            Log.d(TAG, id.toString())
            view?.findNavController()?.navigate(R.id.songDetailFragment, bundle)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setLyricsAdapter()
        getLyrics()
        setProgressBarAccordingToLoadState()
    }

    private fun setLyricsAdapter() {
        binding.productsRecyclerView.adapter = adapter
    }

    private fun getLyrics() {
        lifecycleScope.launch {
            viewModel.flow.collectLatest {
                adapter.submitData(it)
            }
        }
    }

    private fun setProgressBarAccordingToLoadState() {
        lifecycleScope.launch {
            adapter.loadStateFlow.collectLatest {
                binding.progressBar.isVisible = it.append is LoadState.Loading
            }
        }
    }
}

我目前正在使用 FirestorePagingAdapter,它运行良好。对于那些在第 3 页有经验的人,您将如何传递总项目以实现每个项目的点击侦听器。看到类似的问题,但从来没有一个明确的解决方案。挠了一天的头。您的帮助将不胜感激。

编辑 1:添加 HomeFragment.kt

编辑 2:更新了用户建议。点击还是不行。我需要添加空检查。

4

1 回答 1

1

处理适配器内部的点击不是一个好习惯。

适配器关注的只是充当我们数据的桥梁,而不是处理点击的recyclerview。将其传递回片段/活动可以恢复它。其次,使用回调可能会导致内存泄漏,因为它将引用片段/活动。

class YourRecyclerViewAdapter(private val onSelect: (ViewModelLyric?) -> Unit) : PagingDataAdapter<ViewModelLyric, SongViewModelAdapter.SongViewHolder>(Companion) {

    override fun onBindViewHolder(holder: YourViewHolder, position: Int) {
        val lyric = getItem(position) ?: return
        holder.bindLyric(lyric)
    }

    class SongViewHolder(private val binding: YourViewBinding) : RecyclerView.ViewHolder(dataBinding.root) {

        fun bindLyric(yourDataType: ViewModelLyric?, onSelect: (ViewModelLyric?) -> Unit) {
           dataBinding.itemTitle.text = lyric.title
           dataBinding.itemArtist.text = lyric.artist
           dataBinding.root.setOnClickListener {
               onSelect(yourDataType)
           }
        }
    }
}

在您的片段/活动中

// Set this adapter to your recycler view
binding.productsRecyclerView.adapter = YourRecyclerViewAdapter { viewModelLyric-> 
    // Handle click here
}

编辑:

SongViewModelAdapter

class SongViewModelAdapter(private val onSelect: (ViewModelLyric) -> Unit) : PagingDataAdapter<ViewModelLyric, SongViewModelAdapter.SongViewHolder>(Companion) {
    
    val TAG = "SongViewModelAdapter"

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        val dataBinding = LyricDataBinding.inflate(layoutInflater, parent, false)
        return SongViewHolder(dataBinding)
    }

    override fun onBindViewHolder(holder: SongViewHolder, position: Int) {
        val lyric = getItem(position) ?: return
        holder.bindLyric(lyric, onSelect)
    }

    companion object : DiffUtil.ItemCallback<ViewModelLyric>() {
        
        override fun areItemsTheSame(oldItem: ViewModelLyric, newItem: ViewModelLyric): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: ViewModelLyric, newItem: ViewModelLyric): Boolean {
            return oldItem == newItem
        }
    }

    class SongViewHolder(private val dataBinding: LyricDataBinding) : RecyclerView.ViewHolder(dataBinding.root) {
        
        fun bindLyric(lyric: ViewModelLyric, onSelect: (ViewModelLyric) -> Unit)) {
            dataBinding.itemTitle.text = lyric.title
            dataBinding.itemArtist.text = lyric.artist
            dataBinding.root.setOnClickListener {
                onSelect(lyric)
            }
        }
    }
}

首页片段

@AndroidEntryPoint
class HomeFragment : Fragment() {

    val TAG = "HomeFragment"

    private lateinit var binding : FragmentHomeBinding
    private val viewModel by viewModels<HomeFragmentViewModel>()

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
        binding.productsRecyclerView.adapter = SongViewModelAdapter(::onSelect)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        getLyrics()
        setProgressBarAccordingToLoadState()
    }

    private fun onSelect(lyric: ViewModelLyric) {
        // handle click here
    }

    private fun getLyrics() {
        lifecycleScope.launch {
            viewModel.flow.collectLatest {
                binding.adapter.submitData(it)
            }
        }
    }

    private fun setProgressBarAccordingToLoadState() {
        lifecycleScope.launch {
            adapter.loadStateFlow.collectLatest {
                binding.progressBar.isVisible = it.append is LoadState.Loading
            }
        }
    }
}
于 2021-04-13T02:45:35.383 回答