什么是回调函数?


Answers:


680

由于该死的东西的名字,开发人员常常对回调是什么感到困惑。

回调函数是一个函数,它是:

  • 可通过另一个功能访问,并且
  • 如果第一个函数完成,则在第一个函数之后调用

设想回调函数如何工作的一种好方法是,它是传递给它的函数的“ 后面调用的函数。

也许更好的名字应该是“ call after”功能。

这种构造对于异步行为非常有用,在异步行为中,我们希望每当前一个事件完成时就进行一次活动。

伪代码:

// A function which accepts another function as an argument
// (and will automatically invoke that function when it completes - note that there is no explicit call to callbackFunction)
funct printANumber(int number, funct callbackFunction) {
    printout("The number you provided is: " + number);
}

// a function which we will use in a driver function as a callback function
funct printFinishMessage() {
    printout("I have finished printing numbers.");
}

// Driver method
funct event() {
   printANumber(6, printFinishMessage);
}

如果调用event()的结果:

The number you provided is: 6
I have finished printing numbers.

这里的输出顺序很重要。由于回调函数是在以后调用的,因此“我已经完成打印号码”的打印是最后而不是首先打印。

所谓的回调是由于其与指针语言一起使用。如果您不使用其中之一,请不要使用“回调”这个名称。只需了解一下,它只是描述一个方法的名称,该方法作为另一个方法的参数提供,这样,当调用父方法(无论条件如何,例如单击按钮,计时器滴答声等)且其方法主体完成时,然后调用回调函数。

某些语言支持以下结构,其中支持多个回调函数参数,并根据父函数的完成方式进行调用(即,如果父函数成功完成,则调用一个回调,如果父函数抛出一个a,则调用另一个回调。具体错误等)。


31
您的示例很棒,但我不明白为什么该术语是“回调”。意义生命何时被“召回”?
CodyBugstein 2013年

4
您好,关于once its parent method completes, the function which this argument represents is then called。因此,如果将函数作为参数传递给另一个函数,但从父函数运行时的中间调用,则该函数parent(cb) {dostuff1(); cb(); dostuff2()}不被视为callback函数吗?
Max Yari 2015年

2
@MaxYari:恕我直言,它仍然被认为是回调。这里重要的是父functin将以某种方式使用输入函数(又名回调)。可以在中间或结尾或条件满足时调用它。
Kamran Bigdely

12
@ 8bitjunkie谢谢-但是在printANumber函数中在何处调用了meanOfLife方法?
BKSpurgeon '16

2
这根本不是真的:“在第一个功能完成后会自动调用”。根本不需要执行回调,更不用说自动执行回调了。实际上,在父函数完成之前完成回调并不罕见。我非常不喜欢人们如何将回调描述为“稍后”执行的函数。这对正在学习它们的人非常困惑。简而言之,回调函数只是作为参数传递给其他函数的函数。期。更好的解释将包括解释函数引用的WHY回调。
约旦

224

不透明定义

回调函数是您提供给另一段代码的功能,允许该代码调用该函数。

人为的例子

你为什么想做这个?假设有一个您需要调用的服务。如果服务立即返回,则您只需:

  1. 称它为
  2. 等待结果
  3. 结果输入后继续

例如,假设服务是factorial功能。当您需要的值时5!,您将调用factorial(5),并且将发生以下步骤:

  1. 您当前的执行位置已保存(在堆栈上,但这并不重要)

  2. 执行移交给 factorial

  3. factorial完成时,它会将结果的地方,你可以得到它

  4. 执行返回到[1]中的位置

现在假设factorial花费了很长时间,因为您要给它提供大量的数据,并且它需要在某些超级计算集群中运行。假设您预计需要5分钟才能返回结果。你可以:

  1. 保持设计并在晚上入睡时运行程序,这样就不会有一半时间盯着屏幕

  2. 设计程序做其他的事情,而factorial在做它的事

如果选择第二个选项,则回调可能对您有用。

端到端设计

为了利用回调模式,您想要的是能够factorial通过以下方式调用:

factorial(really_big_number, what_to_do_with_the_result)

第二个参数,what_to_do_with_the_result是您发送给的函数factorial,希望可以factorial在返回结果之前对其进行调用。

是的,这意味着factorial需要编写支持回调的信息。

现在假设您希望能够将参数传递给回调。现在您不能了,因为您不会再称呼它了factorial。因此factorial需要编写以允许您传入参数,并且它将在调用它时将它们交给您的回调。它可能看起来像这样:

factorial (number, callback, params)
{
    result = number!   // i can make up operators in my pseudocode
    callback (result, params)
}

现在factorial允许这种模式,您的回调可能如下所示:

logIt (number, logger)
{
    logger.log(number)
}

和你的呼叫factorial

factorial(42, logIt, logger)

如果您要退货logIt怎么办?好吧,你不能,因为factorial没有注意它。

那么,为什么不能factorial只返回回调返回的内容呢?

使其不阻塞

由于执行是要在factorial完成时移交给回调,因此它实际上不应向调用者返回任何内容。理想情况下,它将以某种方式在另一个线程/进程/机器中启动其工作并立即返回,以便您可以继续操作,也许是这样的:

factorial(param_1, param_2, ...)
{
    new factorial_worker_task(param_1, param_2, ...);
    return;
}

现在,这是一个“异步调用”,这意味着当您调用它时,它会立即返回,但尚未真正完成其工作。因此,您确实需要机制来对其进行检查,并在完成时获得其结果,并且您的程序在此过程中变得越来越复杂。

顺便说一句,使用此模式,factorial_worker_task可以异步启动回调并立即返回。

所以你会怎么做?

答案是保持在回调模式之内。每当你想写

a = f()
g(a)

并且f将被异步调用,您将改为

f(g)

在哪里g作为回调传递。

这从根本上改变了程序的流拓扑,并需要一些习惯。

您的编程语言可以为您提供即时创建函数的方式,对您有很大帮助。在紧接上面的代码中,该函数g可能与一样小print (2*a+1)。如果您的语言要求您将其定义为具有完全不必要的名称和签名的单独函数,那么如果您频繁使用此模式,您的生活将变得不愉快。

另一方面,如果您的语言允许您创建lambda,那么您的状态会好得多。然后,您将最终编写类似

f( func(a) { print(2*a+1); })

真是太好了。

如何传递回调

您如何将回调函数传递给factorial?好吧,您可以通过多种方式来做到这一点。

  1. 如果被调用的函数在同一进程中运行,则可以传递一个函数指针

  2. 或者,也许您想fn name --> fn ptr在程序中维护一个字典,在这种情况下,您可以传递名称

  3. 也许您的语言允许您就地定义函数,可能是lambda!在内部,它正在创建某种对象并传递一个指针,但是您不必为此担心。

  4. 也许您正在调用的函数正在完全独立的机器上运行,并且您正在使用诸如HTTP之类的网络协议来调用它。您可以将回调作为HTTP可调用函数公开,并传递其URL。

你明白了。

近期回调的兴起

在我们进入的这个网络时代,我们调用的服务通常是通过网络进行的。我们通常对这些服务没有任何控制权,即我们没有编写它们,不维护它们,无法确保它们正常运行或性能如何。

但是我们不能期望我们的程序在等待这些服务响应时会阻塞。意识到这一点,服务提供商经常使用回调模式来设计API。

JavaScript非常好地支持回调,例如使用lambda和闭包。在JavaScript世界中,浏览器和服务器上都有很多活动。甚至还有针对移动设备开发的JavaScript平台。

随着我们的前进,越来越多的人将在编写异步代码,对此的理解将至关重要。


1
一个概念很好地解释了..!:)
piyushGoyal,2015年

很好的解释,+ 1。
Lingamurthy CS

1
这是所有其他方法中的最佳答案。请赞成。
Abhishek Nalin

3
完美地解释了一切。希望我能再次投票赞成。
Yogesh Yadav

是的,我了解lambas如何在javascript和ruby中工作。和Java 8,但Java的旧版本没有使用lambas,而是使用了类,我想知道这种回调是如何工作的。仍然是另一种更好的答案。
多纳托

96

请注意,回调是一个词。

维基百科的回调页面对此进行了很好的解释。

维基百科页面的报价:

在计算机编程中,回调是对可执行代码或一段可执行代码的引用,该代码作为参数传递给其他代码。这允许较低层的软件层调用在较高层中定义的子例程(或函数)。


14
提出答案的好方法。
Chathuranga Chandrasekara,2009年

1
这也以不同的方式导致了答案。名词“ callback”是被称为“ callback”的名词,其含义与通过shutdown进行关闭的方式相同,而用于登录的则是登录名。
匿名

22
这本来可以是评论-基本上是指向Wikipedia的链接
CodyBugstein 2013年

Wikipedia实际上拥有一些很棒的编程知识。我总是觉得用“我要回电话给...”这句话来最好地解释“回叫”一词
托马斯

javascriptissexy.com/…上有很好的解释;我将在这里转贴;回调函数是一个作为参数传递给另一个函数的函数,该回调函数在otherFunction内部调用或执行。///请注意click方法的参数中的项目是一个函数,而不是变量。 );}); 如您在前面的示例中看到的,我们将函数作为参数传递给click方法以使其执行–
MarcoZen 2015年

46

外行的回答是,在某个事件发生后或处理了一些代码之后,它不是由您而是由用户或浏览器调用的函数。


42

回调函数是在满足特定条件时应调用的函数。回调函数不是立即被调用,而是在将来的某个时刻被调用。

通常,它在启动将异步完成的任务(即将在调用函数返回后的一段时间内完成)时使用。

例如,请求网页的函数可能要求其调用者提供一个回调函数,该函数将在网页下载完成后被调用。


在您的第一句话中,您说过,"...when a condition is met"但我认为当父函数完成执行时便会调用回调,并且回调不依赖于条件(?)。
Ojonugwa Jude Ochalifu 2014年

“确定条件”仅意味着它们通常是出于某种原因而不是随机地被召唤。当父/创建者仍在执行时,可以调用回调-如果程序员不希望这样做,则可能导致竞争。
Thomas Bratt 2014年

Okay.Thanks的澄清
Ojonugwa裘德Ochalifu

34

回叫最容易用电话系统来描述。功能呼叫类似于打电话给某人,问一个问题,得到答案并挂断电话。添加回叫会改变类比,以便在问了她一个问题之后,还给了她您的姓名和电话号码,以便她可以用答案给您回电。

-Paul Jakubik,“ C ++中的回调实现”


1
那我的名字和电话号码是个函数吗?
Koray Tugay

不,如果“ callback”是一个好名字,那将是一个比喻:您要求电话接线员打个电话。结束。
gherson

33

我相信这种“回调”行话在很多地方被错误地使用。我的定义是这样的:

回调函数是您传递给某人并让他们在某个时间点调用的函数。

我认为人们只是阅读了Wiki定义的第一句话:

回调是对可执行代码或一段可执行代码的引用,该代码作为参数传递给其他代码。

我一直在使用许多API,请参见各种不良示例。很多人倾向于将函数指针(对可执行代码的引用)或匿名函数(可执行代码的一部分)命名为“回调”,如果它们只是函数,为什么还要为此命名呢?

实际上,Wiki定义中只有第二句话揭示了回调函数和普通函数之间的区别:

这允许较低层的软件层调用在较高层中定义的子例程(或函数)。

所以区别在于您将要传递谁,以及传递的函数将如何被调用。如果仅定义一个函数并将其传递给另一个函数并在该函数主体中直接调用它,则不要将其称为回调。定义说您传入的函数将被“较低级”函数调用。

我希望人们可以在模棱两可的上下文中停止使用此词,它不能帮助人们更好地理解,只会变得更糟。


2
您的回答很有道理...但是我很难想象它。你能给个例子吗?
CodyBugstein

3
@Zane Wong ::在上一本书中,您写了“定义说,传入的函数将由“较低级”函数调用。” 您能否解释一下下级功能的含义?举个例子更好。
Viku 2014年

一个例子会很不错
Yousuf Azad

1
我认为经典函数调用和回调样式之间的区别在于链接到依赖方向:如果模块A依赖于(“使用”)模块B,则A调用B的函数,而不是回调。如果A将对他的函数的引用传递给B,则B调用A的函数,这是回调:与模块依赖项相比,该调用向后进行。
XouDo

30

让我们保持简单。什么是回叫功能?

寓言和类比的例子

我有秘书 我每天都要求她:(i)在邮局放下公司的外发邮件,然后她这样做之后,去做:(ii)我在其中一张便笺上为她写的任何任务。

现在,便笺上的任务是什么?任务每天都有所不同。

假设在这一天,我要求她打印一些文件。因此,我将其写在便笺上,然后将其与她需要发布的外出邮件一起固定在她的桌子上。

综上所述:

  1. 首先,她需要放下邮件,
  2. 后立即做到这一点,她需要打印了一些文件。

回叫功能是第二个任务:打印这些文档。因为它是在邮件投递之后完成的,而且还因为告诉她打印文档的便条纸与她需要邮寄的邮件一起发送给了她。

现在让我们将其与编程词汇结合起来

  • 在这种情况下,方法名称为:DropOffMail。
  • 回调函数为:PrintOffDocuments。PrintOffDocuments是回调函数,因为我们希望秘书仅在DropOffMail运行之后才这样做。
  • 因此,我会将“ PrintOffDocuments”作为“参数”传递给DropOffMail方法。这一点很重要。

仅此而已。而已。希望为您解决问题-如果没有,请发表评论,我会尽力澄清。


18

这使回调听起来像方法末尾的return语句。

我不确定那是什么。

我认为回调实际上是对函数的调用,这是由于另一个函数被调用并完成的结果。

我还认为回调是为了解决原始调用,它的意思是“嘿!您要的东西?我已经做到了-只是想让您知道-回到您的身边”。


1
+1用于质疑回调与返回语句。我曾经被这个问题吸引住了,与我合作的许多毕业生也是如此。
8bitjunkie 2011年

2
好答案-与许多其他答案不同,它帮助我理解了它!
adaam 2014年

18

什么是回调

  • 通常,拨打电话是为了返回某人已收到的电话。
  • 在计算中,回调是一段可执行代码,它作为参数传递给其他代码。当函数完成其工作时(或发生某些事件时),它将调用您的回调函数(它会回调您的名字,也就是您的名字)。

什么是回调函数

  • 回调函数就像一个仆人,当他完成一项任务时会“回调”给他的主人。
  • 一个回调函数是传递给另一个函数的函数(我们称之为其他功能otherFunction)作为参数,并且回调函数被调用(或执行)内otherFunction
    function action(x, y, callback) {
        return callback(x, y);
    }

    function multiplication(x, y) {
        return x * y;
    }

    function addition(x, y) {
        return x + y;
    }

    alert(action(10, 10, multiplication)); // output: 100

    alert(action(10, 10, addition)); // output: 20

在SOA中,回调允许插件模块从容器/环境访问服务。

打个比方:回调。异步。回调的非阻塞
现实生活示例


回调函数本身并不是高阶函数。它被传递给高阶函数。
danio '16

17

比愚蠢的名字callback更好的名字是Call After。当一个函数满足条件时,或调用另一个函数,即Call After函数,该函数作为参数接收。

而不是硬编码一个函数中的内部函数,而是编写一个函数以接受已经编写的Call After函数作为参数。该呼叫后可能会被称为基于状态变化的函数接收参数检测的代码。


这是一个好主意。我要求“在后面打电话”来尝试解释这一点。我可以在他开创性的博客上看到像马丁·福勒这样的人将“呼吁”作为这些术语的新名词。
8bitjunkie '16

15

回调函数是您为现有函数/方法指定的函数,将在操作完成,需要其他处理等时调用。

例如,在Javascript(或更确切地说是jQuery)中,您可以指定动画结束时要调用的回调参数。

在PHP中,该preg_replace_callback()函数允许您提供一个匹配正则表达式时将调用的函数,并将匹配的字符串作为参数传递。


10

看图片:)这是这样的

主程序使用回调函数名称调用库函数(也可能是系统级函数)。该回调函数可以以多种方式实现。主程序根据需要选择一个回调。

最后,库函数在执行期间调用回调函数。


7
您还介意为此添加文字说明吗?如果图像消失,则此答案将失去所有上下文。
蒂姆·波斯特

别人的文字最好地说明了这一点。我感到唯一缺少的是图像:)

我在这里看到的所有冗长的描述中,有一个使我走“ ahhhhh,现在我看到了它的用法”。进行投票。
DiBosco

7

这个问题的简单答案是,回调函数是通过函数指针调用的函数。如果将一个函数的指针(地址)作为参数传递给另一个函数,则当该指针用于调用该函数时,它指向该函数,即表示已进行回调


6

假设我们有一个函数sort(int *arraytobesorted,void (*algorithmchosen)(void)),它可以接受函数指针作为其参数,可以在实现的某个时刻使用它sort()。然后,这里由函数指针寻址的代码algorithmchosen称为回调函数

看到的好处是我们可以选择任何算法,例如:

  1.    algorithmchosen = bubblesort
  2.    algorithmchosen = heapsort
  3.    algorithmchosen = mergesort   ...

例如,这些已通过原型实现:

  1.   `void bubblesort(void)`
  2.   `void heapsort(void)`
  3.   `void mergesort(void)`   ...

这是在面向对象编程中实现多态的概念


javascriptissexy.com/…上有很好的解释;我将在这里转贴;回调函数是一个作为参数传递给另一个函数的函数,该回调函数在otherFunction内部调用或执行。///请注意click方法的参数中的项目是一个函数,而不是变量。 );}); 如您在前面的示例中看到的,我们将函数作为参数传递给click方法以使其执行–
MarcoZen 2015年

4

“在计算机编程中,回调是对可执行代码或一段可执行代码的引用,该代码作为参数传递给其他代码。这允许较低层的软件层调用较高层中定义的子例程(或函数)。” -维基百科

使用函数指针在C中进行回调

在C语言中,回调是使用功能指针实现的。函数指针-顾名思义,它是指向函数的指针。

例如,int(* ptrFunc)();

在这里,ptrFunc是指向不带任何参数并返回整数的函数的指针。不要忘记加括号,否则编译器会假设ptrFunc是一个普通的函数名,它不做任何事情并返回一个指向整数的指针。

这是一些代码来演示函数指针。

#include<stdio.h>
int func(int, int);
int main(void)
{
    int result1,result2;
    /* declaring a pointer to a function which takes
       two int arguments and returns an integer as result */
    int (*ptrFunc)(int,int);

    /* assigning ptrFunc to func's address */                    
    ptrFunc=func;

    /* calling func() through explicit dereference */
    result1 = (*ptrFunc)(10,20);

    /* calling func() through implicit dereference */        
    result2 = ptrFunc(10,20);            
    printf("result1 = %d result2 = %d\n",result1,result2);
    return 0;
}

int func(int x, int y)
{
    return x+y;
}

现在让我们尝试使用函数指针来理解C语言中回调的概念。

完整的程序包含三个文件:callback.c,reg_callback.h和reg_callback.c。

/* callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* callback function definition goes here */
void my_callback(void)
{
    printf("inside my_callback\n");
}

int main(void)
{
    /* initialize function pointer to
    my_callback */
    callback ptr_my_callback=my_callback;                        
    printf("This is a program demonstrating function callback\n");
    /* register our callback function */
    register_callback(ptr_my_callback);                          
    printf("back inside main program\n");
    return 0;
}

/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);


/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
    printf("inside register_callback\n");
    /* calling our callback function my_callback */
    (*ptr_reg_callback)();                               
}

如果我们运行该程序,输出将是

这是一个程序,该程序在主程序内部的register_callback内部的my_callback内部演示函数回调

较高层的函数将较低层的函数作为普通调用来调用,并且回调机制允许较低层的函数通过指向回调函数的指针来调用较高层的函数。

Java使用界面中的回调

Java没有函数指针的概念。它通过其接口机制实现回调机制。在此,我们声明一个接口,该接口具有一个函数,该方法将在被调用者完成其任务时被调用,而不是函数指针。

让我通过一个示例进行演示:

回调接口

public interface Callback
{
    public void notify(Result result);
}

呼叫者或更高级别的班级

public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee

//Other functionality
//Call the Asynctask
ce.doAsynctask();

public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}

被调用者或下层功能

public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}

doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}

使用EventListener模式进行回调

  • 项目清单

此模式用于通知0到n个观察者/侦听器特定任务已完成

  • 项目清单

回调机制和EventListener / Observer机制之间的区别在于,在回调中,被叫方通知单个调用方,而在Eventlisener / Observer中,被叫方可以通知对该事件感兴趣的任何人(该通知可能会转到该事件的其他部分。尚未触发任务的应用程序)

让我通过一个例子来解释。

事件界面

public interface Events {

public void clickEvent();
public void longClickEvent();
}

类小部件

package com.som_itsolutions.training.java.exampleeventlistener;

import java.util.ArrayList;
import java.util.Iterator;

public class Widget implements Events{

    ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>(); 
    ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();

    @Override
    public void clickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnClickEventListener> it = mClickEventListener.iterator();
                while(it.hasNext()){
                    OnClickEventListener li = it.next();
                    li.onClick(this);
                }   
    }
    @Override
    public void longClickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
        while(it.hasNext()){
            OnLongClickEventListener li = it.next();
            li.onLongClick(this);
        }

    }

    public interface OnClickEventListener
    {
        public void onClick (Widget source);
    }

    public interface OnLongClickEventListener
    {
        public void onLongClick (Widget source);
    }

    public void setOnClickEventListner(OnClickEventListener li){
        mClickEventListener.add(li);
    }
    public void setOnLongClickEventListner(OnLongClickEventListener li){
        mLongClickEventListener.add(li);
    }
}

类按钮

public class Button extends Widget{
private String mButtonText;
public Button (){
} 
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}

类复选框

public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}

活动课

包com.som_itsolutions.training.java.exampleeventlistener;

public class Activity implements Widget.OnClickEventListener
{
    public Button mButton;
    public CheckBox mCheckBox;
    private static Activity mActivityHandler;
    public static Activity getActivityHandle(){
        return mActivityHandler;
    }
    public Activity ()
    {
        mActivityHandler = this;
        mButton = new Button();
        mButton.setOnClickEventListner(this);
        mCheckBox = new CheckBox();
        mCheckBox.setOnClickEventListner(this);
        } 
    public void onClick (Widget source)
    {
        if(source == mButton){
            mButton.setButtonText("Thank you for clicking me...");
            System.out.println(((Button) mButton).getButtonText());
        }
        if(source == mCheckBox){
            if(mCheckBox.isChecked()==false){
                mCheckBox.setCheck(true);
                System.out.println("The checkbox is checked...");
            }
            else{
                mCheckBox.setCheck(false);
                System.out.println("The checkbox is not checked...");
            }       
        }
    }
    public void doSomeWork(Widget source){
        source.clickEvent();
    }   
}

其他类

public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event                        //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}

主班

public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}

从上面的代码中可以看到,我们有一个称为事件的接口,该接口基本上列出了应用程序可能发生的所有事件。Widget类是所有UI组件(如Button,Checkbox)的基类。这些UI组件是实际从框架代码接收事件的对象。窗口小部件类实现事件接口,并且它具有两个嵌套接口,即OnClickEventListener和OnLongClickEventListener

这两个接口负责侦听在Widget派生的UI组件(例如Button或Checkbox)上可能发生的事件。因此,如果将本示例与使用Java接口的早期Callback示例进行比较,则这两个接口将用作Callback接口。因此,较高级别的代码(此处的活动)实现了这两个接口。而且,每当窗口小部件发生事件时,就会调用更高级别的代码(或在更高级别的代码中实现的这些接口的方法,在这里为Activity)。

现在让我讨论Callback和Eventlistener模式之间的基本区别。正如我们已经提到的,使用回叫,被叫方只能通知一个呼叫者。但是,对于EventListener模式,应用程序的任何其他部分或类都可以注册按钮或复选框上可能发生的事件。此类的示例是OtherClass。如果您看到OtherClass的代码,则会发现它已将自己注册为ClickEvent的侦听器,该事件可能在Activity中定义的Button中发生。有趣的是,除了活动(调用方)之外,只要在Button上发生click事件,此OtherClass也将得到通知。


避免仅链接答案。答案是“勉强超过一个链接到外部网站” 可能会被删除
昆汀

3

回调函数是您传递(作为引用或指针)到某个函数或对象的函数。此函数或对象将在以后任何时候(可能多次)出于某种目的而调用此函数:

  • 通知任务结束
  • 请求两个项目之间的比较(如c qsort()中的)
  • 报告流程进度
  • 通知事件
  • 委托对象的实例化
  • 委托区域的绘画

...

因此,将回调描述为在另一个函数或任务的末尾被调用的函数会过于简化(即使这是常见的用例)。


2

回调是将一个函数作为参数传递给另一个函数,并在过程完成后调用此函数的想法。

如果您通过上面的出色答案获得了回调的概念,我建议您应该了解其概念的背景。

“是什么让他们(计算机科学家)开发回调?” 您可能会了解到一个正在阻塞的问题。(尤其是阻塞UI),并且回调不是唯一的解决方案。还有很多其他解决方案(例如:线程,期货,承诺...)。


1

一个重要的用法领域是,您将一个函数注册为一个句柄(即回调),然后发送消息/调用某些函数以完成某些工作或处理。现在,在处理完成之后,被调用函数将调用我们的注册函数(即,现在已完成回调),从而指示我们处理已完成。
这个 Wikipedia链接用图形很好地解释了。


1

回调函数,也称为高阶函数,是一个作为参数传递给另一个函数的函数,并且该回调函数在父函数内部被调用(或执行)。

$("#button_1").click(function() {
  alert("button 1 Clicked");
});

在这里,我们将一个函数作为参数传递给click方法。click方法将调用(或执行)我们传递给它的回调函数。


1
回调函数本身并不是高阶函数。它被传递给高阶函数。
danio '16

1

回调函数 一个作为参数传递给另一个函数的函数。

function test_function(){       
 alert("Hello world");  
} 

setTimeout(test_function, 2000);

注意:在上面的示例中,test_function用作setTimeout函数的参数。


1
欢迎使用Stack Overflow!在回答问题之前,请务必阅读现有的答案。已经提供了这个答案。不要重复答案,而要对现有答案进行投票。在这里可以找到一些写出好的答案的准则。
dferenc
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.