📌  相关文章
📜  用于 Android 中 RecyclerView 适配器回调的 Kotlin Lambda 函数

📅  最后修改于: 2022-05-13 01:54:20.068000             🧑  作者: Mango

用于 Android 中 RecyclerView 适配器回调的 Kotlin Lambda 函数

您是否使用过时的Java方式在带有接口的 Android 中创建和处理回调?如果是,那么现在是开启 Kotlin Lambda 函数或高阶函数以创建和处理回调的好时机。这是一种更短、更简单、更容易的方法。

让我们先快速看一下较旧的Java风格的方式

请记住,当您需要在 RecyclerView 项目上实现点击功能时,您会创建一个界面,该界面具有处理 RecyclerView 项目不同点击的所有方法,并在活动/片段中实现所有这些界面功能以执行某些操作(例如:从当前屏幕导航到另一个屏幕或其他屏幕)。然后你通过构造函数将该接口的引用传递给你的适配器。然后我们在适配器中使用该接口来调用/调用其函数以在活动/片段内生成回调。现在看看这个过程有多长,Kotlin 的力量在发挥作用……让我们看看

用于适配器回调的 Kotlin Lambda 函数

首先,告别冗长的界面方式……我们现在将 lambda函数作为参数添加到适配器的构造函数中。我们以 MoviesAdapter 为例,将名为“onItemClicked”的电影列表和 lambda函数作为参数,在我们的 lambda函数“onItemClicked”中,我们添加了电影对象作为参数,以便我们可以在这个 lambda 函数的回调中接收这个电影对象我们的片段/活动。

Kotlin
class MoviesAdapter(
    private var moviesList: List,
    // Here we have added lambda function
    // named 'onItemClicked' as an argument
    // that will itself take movie object as an
    // argument & will return unit means nothing
    private var onItemClicked: ((movie: Movie) -> Unit)
) : RecyclerView.Adapter() {
 
 
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        // Just to show as an example we took layout
        // 'MovieItem' as recyclerview items/views.
        val binding = MovieItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }
 
 
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // getting a movie from movieList &
        // passing in viewholder's bind function
        holder.bind(moviesList[position])
    }
     
    inner class ViewHolder(val binding: MovieItemBinding) : RecyclerView.ViewHolder(binding.root) {
     
        fun bind(movie: Movie) = binding.apply {
            // Just setting movie details to
            // movieName & movieDescription textviews
            tvMovieName.text = movie.name
            tvMovieDescription.text = movie.description
           
            // Adding clickListener to
            // root layout of this item
            root.setOnClickListener {
                // Invoking this lambda function so that
                // it can give callback in our activity/fragment
                // We are also passing movie object
                // in it while invoking/calling it
                 onItemClicked(movie)
            }
        }
    }
 
    override fun getItemCount(): Int {
        return languageList.size
    }
}


Kotlin
class MovieListFragment : Fragment() {
 
    // Declaring moviesAdapter with lateinit
    private lateinit var moviesAdapter: MoviesAdapter
   
    // using viewbinding
    private var _binding: FragmentMovieListBinding? = null
    private val binding get() = _binding!!
 
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentMovieListBinding.inflate(inflater, container, false)
        return binding.root
    }
 
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
 
        // Assume that getMoviesList() is returning
        // list of movies let's say from api call
        val moviesList : List = getMoviesList()
         
        // Setting up movies recyclerview
        binding.moviesRecyclerView.layoutManager = LinearLayoutManager(requireContext())
        binding.moviesRecyclerView.setHasFixedSize(true)
      
        // Instantiating moviesAdapter & passing
        // lambda function in it's constructor
        moviesAdapter = MoviesAdapter(moviesList) { it: Movie ->
            // Here we'll receive callback of
            // every recyclerview item click
            // Now, perform any action here.
            // for ex: navigate to different screen
        }
         
        // Setting adapter to moviesRecyclerView
        binding.moviesRecyclerView.adapter = moviesAdapter
    }
}


在这个例子中,我们在 RecyclerView Adapter 中使用 Viewbinding。现在让我们进入 Viewholder 的绑定函数,在其中,我们只是简单地设置电影详细信息,如电影名称、对 RecyclerView 项目的描述,我们必须为每个 RecyclerView 项目添加点击功能,以便我们可以在点击时执行一些操作。因此,在我们项目根的 clickListener 中,我们实际上是在调用我们的 lambda函数onItemClicked 并在其中传递电影。所以这样我们会在我们的片段/活动中收到一个回调,因为它会在项目点击时被调用。现在让我们看看如何……

让我们创建适配器的对象并在其中传递 Lambda函数

我们这里以 MovieListFragment 为例:

科特林

class MovieListFragment : Fragment() {
 
    // Declaring moviesAdapter with lateinit
    private lateinit var moviesAdapter: MoviesAdapter
   
    // using viewbinding
    private var _binding: FragmentMovieListBinding? = null
    private val binding get() = _binding!!
 
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentMovieListBinding.inflate(inflater, container, false)
        return binding.root
    }
 
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
 
        // Assume that getMoviesList() is returning
        // list of movies let's say from api call
        val moviesList : List = getMoviesList()
         
        // Setting up movies recyclerview
        binding.moviesRecyclerView.layoutManager = LinearLayoutManager(requireContext())
        binding.moviesRecyclerView.setHasFixedSize(true)
      
        // Instantiating moviesAdapter & passing
        // lambda function in it's constructor
        moviesAdapter = MoviesAdapter(moviesList) { it: Movie ->
            // Here we'll receive callback of
            // every recyclerview item click
            // Now, perform any action here.
            // for ex: navigate to different screen
        }
         
        // Setting adapter to moviesRecyclerView
        binding.moviesRecyclerView.adapter = moviesAdapter
    }
}

在这里,我们只是实例化了 moviesAdapter ,因此它需要我们在其构造函数中传递电影和 lambda 函数的列表。所以现在,在 lambda函数块中,我们得到一个电影对象,这意味着每当从适配器调用这个 lambda函数时,我们都会在这里收到一个带有电影对象的回调,现在我们可以执行任何我们想要的操作想要在这个 lambda函数块下。就是这样,这就是我们将 Kotlin Lambda 函数用于 RecyclerView 适配器回调而不是接口的方式。