No0:callback应用场景
虽然经过一段时间对android源码的研究,初步理解如何从app将参数设置到Linux kernel(高通camera部分),但对上层如何获得底层数据困惑不已,最近通过对android frameworks、hal、application层代码的分析,有了初步理解,作简要总结,会在下一篇文章介绍具体实现细节:
上层通过使用callback机制来获得底层数据流-(preview/recording/takePicture)。
No1:何为callback
1) 宽泛解释
通过函数指针调用的函数
定义:
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
CALLBACK实现的机制
实现机制:
[1]定义一个回调函数;
[2]提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;
[3]当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。
优点:
因为使用此函数可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的函数的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。
2) 具体解释:
定义:
模块A有一个函数fun,它向模块B传递fun的地址,然后在B里面发生某种事件(event)时,通过从A里面传递过来的fun函数的地址调用fun函数,通知A发生了什么事情,让A作出相应反应,则fun函数称为回调函数,即回调就是一种利用函数指针进行函数调用的过程。
实现机制:
[1] B模块里先定义回调函数类型,、回调函数指针和提供给A模块的接口函数(用于注册callback函数)
typedef void (CALLBACK *cbkSendCmdToMain) (AnsiString sCmd);
cbkSendCmdToMain SendCmdToMain;
void setCallback(CALLBACK *callback); //接口函数
这样SendCmdToMain就是一个指向拥有一个AnsiString形参, 返回值为void的函数指针.
这样, 在接收到命令时, 就可以调用这个函数
[2] 主模块里调用setCallback函数来注册这个回调函数.
在A模块里callback函数具体实现
void CALLBACK SendCmdFun(AnsiString sCmd); //声明
void CALLBACK SendCmdFun(AnsiString sCmd); //定义
{
ShowMessage(sCmd);
}
调用setCallback函数注册回调函数:
setCallback(SendCmdFun);
注意:回调函数一般都要声明为全局的. 如果要在类里使用回调函数, 前面需要加上 static , 其实也相当于全局的.
优点:
为什么要用回调呢?比如我要写一个子模块给你用, 来接收远程socket发来的命令.当我接收到命令后, 需要调用你的主模块的函数, 来进行相应的处理.但是我不知道你要用哪个函数来处理这个命令, 我也不知道你的主模块是什么.cpp或者.h, 或者说, 根本不用关心你在主模块里怎么处理它, 也不应该关心用什么函数处理它。
注:
想知道回调函数在实际中有什么作用?
先假设有这样一种情况:
我们要编写一个库,它提供了某些排序算法的实现(如冒泡排序、快速排序、shell排序、shake排序等等),为了能让库更加通用,不想在函数中嵌入排序逻辑,而让使用者来实现相应的逻辑;
或者,能让库可用于多种数据类型(int、float、string),此时,该怎么办呢?可以使用函数指针,并进行回调。
回调可用于通知机制:
例如,有时要在A程序中设置一个计时器,每到一定时间,A程序会得到相应的通知,但通知机制的实现者对A程序一无所知。那么,就需一个具有特定原型的函数指针进行回调,通知A程序事件已经发生。
实际上,API使用一个回调函数SetTimer()来通知计时器。如果没有提供回调函数,它还会把一个消息发往程序的消息队列。
另一个使用回调机制的API函数是EnumWindow(),它枚举屏幕上所有的顶层窗口,每个窗口都可以通过它调用另一个程序提供的函数,并传递窗口的处理程序。例如:如果被调用者返回一个值,就继续进行迭代;否则,退出。
EnumWindow()并不关心被调用者在何处,也不关心被调用者用它传递的处理程序做了什么,它只关心返回值,因为基于返回值,它将继续执行或退出。
不管怎么说,回调函数是继承自C语言的。在C++中,应只在与C代码建立接口或与已有的回调接口打交道时,才使用回调函数。除了上述情况,在C++中应使用虚拟方法或仿函数(functor),而不是回调函数。
卫朋
人人都是产品经理受邀专栏作家,CSDN 嵌入式领域新星创作者、资深技术博主。2020 年 8 月开始写产品相关内容,截至目前,人人都是产品经理单渠道阅读 56 万+,鸟哥笔记单渠道阅读200 万+,CSDN 单渠道阅读 210 万+,51CTO单渠道阅读 180 万+。
卫朋入围2021/2022年人人都是产品经理平台年度作者,光环国际学习社区首批原创者、知识合作伙伴,商业新知 2021 年度产品十佳创作者,腾讯调研云2022年达人榜第三名。
文章被人人都是产品经理、CSDN、华为云、运营派、产品壹佰、鸟哥笔记、光环国际、商业新知、腾讯调研云等头部垂直类媒体转载。文章见仁见智,各位看官可策略性选择对于自己有用的部分。