【问题标题】:RecyclerView adapter onItemClick event not triggeringRecyclerView 适配器 onItemClick 事件未触发
【发布时间】:2020-11-10 20:19:35
【问题描述】:

我是一名 Java Android 开发人员,试图在 Kotlin 中重新学习 RecyclerView 适配器。

我有一个包含 RecyclerView 的片段。我在 Fragment 类中初始化了适配器和 OnItemClickListener。但是我的 onItemClick() 永远不会被触发。 Log.d 从不显示。

BreakingNewsFragment.kt

class BreakingNewsFragment : Fragment(R.layout.fragment_breaking_news) {

lateinit var viewModel: NewsViewModel
lateinit var newsAdapter: NewsAdapter

val TAG = "BreakingNewsFragment"

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewModel = (activity as NewsActivity).viewModel
    setupRecyclerView()
    Log.d(TAG, "onitemclick") // this shows!

    newsAdapter.setOnItemClickListener {
        Log.d(TAG, "onitemclick") // this won't show
        val bundle = Bundle().apply {
            putSerializable("article", it)
        }
        findNavController().navigate(
            R.id.action_breakingNewsFragment_to_articleFragment,
            bundle
        )
    }

    viewModel.breakingNews.observe(viewLifecycleOwner, Observer { response ->
        when(response) {
            is Resource.Success -> {
                hideProgressBar()
                response.data?.let { newsResponse ->
                    newsAdapter.differ.submitList(newsResponse.articles)
                }
            }
            is Resource.Error -> {
                hideProgressBar()
                response.message?.let {message ->
                    Log.e(TAG, "An error occurred: $message")
                }
            }
            is Resource.Loading -> {
                showProgressBar()
            }
        }
    })
}

private fun hideProgressBar() {
    paginationProgressBar.visibility = View.INVISIBLE
}

private fun showProgressBar() {
    paginationProgressBar.visibility = View.VISIBLE
}

private fun setupRecyclerView() {
    newsAdapter = NewsAdapter()
    rvBreakingNews.apply {
        adapter = newsAdapter
        layoutManager = LinearLayoutManager(activity)
    }
}
}

NewsAdapter.kt

class NewsAdapter : RecyclerView.Adapter<NewsAdapter.ArticleViewHolder>() {

inner class ArticleViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)

private val differCallback = object : DiffUtil.ItemCallback<Article>() {
    override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
        // can't compare article IDs; articles from API do not have IDs. but URLs are unique for each article so we can compare those
        return oldItem.url == newItem.url
    }

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

// instead of using a standard list to store objects, use this ListDiffer to calculate differences between lists
val differ = AsyncListDiffer(this, differCallback)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
    return ArticleViewHolder(
        LayoutInflater.from(parent.context).inflate(R.layout.item_article_preview, parent,false)
    )
}

override fun getItemCount(): Int {
    return differ.currentList.size
}

override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
    val article = differ.currentList[position]
    holder.itemView.apply { // apply: reference views directly
        Glide.with(this).load(article.urlToImage).into(ivArticleImage)
        tvSource.text = article.source.name
        tvTitle.text = article.title
        tvDescription.text = article.description
        tvPublishedAt.text = article.publishedAt
        setOnItemClickListener { onItemClickListener?.let( { it(article) }) }
    }
}

private var onItemClickListener: ((Article) -> Unit)? = null // pass current article to function, open webview page from there

fun setOnItemClickListener(listener: (Article) -> Unit) {
    onItemClickListener = listener
}
}

【问题讨论】:

    标签: android kotlin android-recyclerview


    【解决方案1】:

    在您的holder.itemView.apply { 中,您没有将回调分配给您的 holder.itemView;您正在调用setOnItemClickListener,它所做的只是更改您的onItemClickListener,这实际上是一个局部变量,而不是视图中的回调函数。

    你想做的是:

    
    holder.itemView.apply { // apply: reference views directly
            ..
            setOnClickListener { onItemClickListener?.let( { it(article) }) }
        }
    

    (注意,这是setOnClickListener,不是setOn*Item*ClickListener

    我建议您将 var onItemClickListener 设为非私有,直接从适配器外部使用它,然后删除 fun setOnItemClickListener()... 在 Kotlin 世界中,像这样的公共 vars 会被编译为具有它们的设置器,所以你真的不再需要 Java 样式设置器了。

    【讨论】:

    • 感谢指正!一旦我将 onItemClickListener 作为公共变量,我是否必须使用' newsAdapter.apply { ... }' 从 Fragment 设置它?
    • 是的,就像您通常使用 setter 一样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多