Android中回调的简单使用

283 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

Android开发中回调用的最多的地方,应该属Adapter、各种监听事件和处理数据时的异步调用。如:在Activity/Fragment中响应RecyclerView中的动作,获得从RecyclerView中传递出来的数据,在Dialog外部对内部按钮点击事件的处理等。

什么是回调? 如图:

截屏2022-05-30 下午9.02.23.png

类A实现了接口C实例instance,接口中的方法可以带有参数和返回值。类B获得instance后,根据情况调用instance的方法。实际调用了类A实现的方法,类A作出响应动作,根据传入参数返回值给类B。即类B通过接口C实例调用了类A实现的接口C方法。

在Java中,接口回调必须要声明一个接口。但在Kotlin中,可以直接使用匿名函数代替接口。但如果接口中有多个函数的话,还是使用接口更方便。

以在Activity中响应RecyclerView点击事件弹出弹窗为例子,Adapter部分代码(类B、接口C):

class AdressBookAdapter : RecyclerView.Adapter<AdressBookAdapter.ViewHolder>() {

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        //TODO......
        fun init(model: AdressBookModel) {
            //TODO......
            itemView.setOnClickListener {
                mClickListener?.clickItem(model)   //类B调用接口C方法
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.rv_item_adress_book, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.init(data.get(position))
    }

    override fun getItemCount(): Int = data.size

    /**
     * data
     */
    private val data = arrayListOf<AdressBookModel>()

    fun setData(list: List<AdressBookModel>) {
        data.clear()
        data.addAll(list)
        notifyDataSetChanged()
    }

    /**
     * ListenerInterface (接口C)
     */
    interface ClickListener {
        fun clickItem(modle: AdressBookModel)
    }

    //接口实例
    var mClickListener: ClickListener? = null

}

Activity部分代码(类A):

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    //类A实现接口C方法
    val clickListener=object :AdressBookAdapter.ClickListener{
        override fun clickItem(modle: AdressBookModel) {
            showAdressDlg(modle)    //弹出弹窗
        }
    }

    rv.run {
        layoutManager =
            LinearLayoutManager(this@MainActivity, LinearLayoutManager.VERTICAL, false)
        adapter = this@MainActivity.adapter.apply {
            this.mClickListener=clickListener    //类A将接口C实例传递给类B
        }
    }
}

这是接口回调的实现。如果使用匿名函数,该如何实现呢?还是举同样的例子。

Adapter部分代码:

class AdressBookAdapter : RecyclerView.Adapter<AdressBookAdapter.ViewHolder>() {

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        //TODO......
        fun init(model: AdressBookModel) {
            //TODO......
            itemView.setOnClickListener {
                clickItem(model)    //调用匿名函数
            }
        }
    }
    
    //重写RecyclerView.Adapter函数和数据设置部分没有变化
     

    //将监听接口替换为匿名函数
    //声明一个匿名函数,带一个AdressBookModel参数,返回值为Unit,函数体为空
    var clickItem: (AdressBookModel) -> Unit = {}

}

Activity部分:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    rv.run {
        layoutManager =
            LinearLayoutManager(this@MainActivity, LinearLayoutManager.VERTICAL, false)
        adapter = this@MainActivity.adapter.apply {
            clickItem = {    //实现Adapter的匿名函数
                showAdressDlg(it)
            }
        }
    }
    getData()
}

以上是回调的两种实现方式:通过接口实现和通过匿名函数实现。 通过匿名函数实现比通过接口实现更加方便,代码更加简洁。

掌握接口回调的思想,能够解决UI组件间交互的大部分问题。