用于 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 适配器回调而不是接口的方式。
Note: We can use these lambda functions for creating/handling callbacks not only in recyclerview’s adapter but wherever we want this type of functionality in our project.