„In der Computerprogrammierung ist ein Rückruf eine Referenz auf ausführbaren Code oder einen ausführbaren Code, der als Argument an anderen Code übergeben wird. Auf diese Weise kann eine untergeordnete Softwareschicht eine Unterroutine (oder Funktion) aufrufen, die in einer übergeordneten Ebene definiert ist. “ - Wikipedia
Rückruf in C mit Funktionszeiger
In C wird der Rückruf mit dem Funktionszeiger implementiert. Funktionszeiger - ist, wie der Name schon sagt, ein Zeiger auf eine Funktion.
Zum Beispiel int (* ptrFunc) ();
Hier ist ptrFunc ein Zeiger auf eine Funktion, die keine Argumente akzeptiert und eine Ganzzahl zurückgibt. Vergessen Sie NICHT, in Klammern zu setzen, sonst geht der Compiler davon aus, dass ptrFunc ein normaler Funktionsname ist, der nichts nimmt und einen Zeiger auf eine Ganzzahl zurückgibt.
Hier ist ein Code zur Demonstration des Funktionszeigers.
#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;
}
Versuchen wir nun, das Konzept des Rückrufs in C mithilfe des Funktionszeigers zu verstehen.
Das vollständige Programm enthält drei Dateien: callback.c, reg_callback.h und 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)();
}
Wenn wir dieses Programm ausführen, wird die Ausgabe sein
Dies ist ein Programm, das den Funktionsrückruf in register_callback in my_callback zurück im Hauptprogramm demonstriert
Die Funktion der höheren Schicht ruft eine Funktion der niedrigeren Schicht als normalen Aufruf auf, und der Rückrufmechanismus ermöglicht es der Funktion der unteren Schicht, die Funktion der höheren Schicht über einen Zeiger auf eine Rückruffunktion aufzurufen.
Rückruf in Java über die Schnittstelle
Java hat nicht das Konzept eines Funktionszeigers. Es implementiert den Rückrufmechanismus über seinen Schnittstellenmechanismus. Hier deklarieren wir anstelle eines Funktionszeigers eine Schnittstelle mit einer Methode, die aufgerufen wird, wenn der Angerufene seine Aufgabe beendet
Lassen Sie es mich anhand eines Beispiels demonstrieren:
Die Rückrufschnittstelle
public interface Callback
{
public void notify(Result result);
}
Der Anrufer oder die höhere Klasse
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
}
}
Die Callee oder die untere Schichtfunktion
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
}
}
Rückruf mit EventListener-Muster
Dieses Muster wird verwendet, um 0 bis n Anzahlen von Beobachtern / Zuhörern zu benachrichtigen, dass eine bestimmte Aufgabe beendet wurde
Der Unterschied zwischen dem Rückrufmechanismus und dem EventListener / Observer-Mechanismus besteht darin, dass der Angerufene beim Rückruf den einzelnen Anrufer benachrichtigt, während der Angerufene bei Eventlisener / Observer jeden benachrichtigen kann, der an diesem Ereignis interessiert ist (die Benachrichtigung kann an einige andere Teile des Anwendung, die die Aufgabe nicht ausgelöst hat)
Lassen Sie es mich anhand eines Beispiels erklären.
Die Ereignisschnittstelle
public interface Events {
public void clickEvent();
public void longClickEvent();
}
Klassen-Widget
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);
}
}
Klassenschaltfläche
public class Button extends Widget{
private String mButtonText;
public Button (){
}
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}
Klassen-Kontrollkästchen
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;
}
}
Aktivitätsklasse
Paket 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();
}
}
Andere Klasse
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...");
}
}
Hauptklasse
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);
}
}
Wie Sie dem obigen Code entnehmen können, haben wir eine Schnittstelle namens events, die im Grunde alle Ereignisse auflistet, die für unsere Anwendung auftreten können. Die Widget-Klasse ist die Basisklasse für alle UI-Komponenten wie Button, Checkbox. Diese UI-Komponenten sind die Objekte, die die Ereignisse tatsächlich vom Framework-Code empfangen. Die Widget-Klasse implementiert die Ereignisschnittstelle und verfügt außerdem über zwei verschachtelte Schnittstellen, nämlich OnClickEventListener und OnLongClickEventListener
Diese beiden Schnittstellen sind für das Abhören von Ereignissen verantwortlich, die auf den vom Widget abgeleiteten UI-Komponenten wie Button oder Checkbox auftreten können. Wenn wir dieses Beispiel mit dem früheren Callback-Beispiel unter Verwendung der Java-Schnittstelle vergleichen, fungieren diese beiden Schnittstellen als Callback-Schnittstelle. Der übergeordnete Code (Here Activity) implementiert diese beiden Schnittstellen. Und wenn ein Ereignis in einem Widget auftritt, wird der Code auf höherer Ebene (oder die Methode dieser Schnittstellen, die im Code auf höherer Ebene implementiert ist, der hier Aktivität ist) aufgerufen.
Lassen Sie mich nun den grundlegenden Unterschied zwischen Callback- und Eventlistener-Muster diskutieren. Wie bereits erwähnt, kann der Callee mit Callback nur einen einzigen Anrufer benachrichtigen. Im Fall eines EventListener-Musters kann sich jedoch jeder andere Teil oder jede andere Klasse der Anwendung für die Ereignisse registrieren, die auf der Schaltfläche oder dem Kontrollkästchen auftreten können. Das Beispiel für diese Art von Klasse ist die OtherClass. Wenn Sie den Code der OtherClass sehen, werden Sie feststellen, dass sie sich als Listener für das ClickEvent registriert hat, das in der in der Aktivität definierten Schaltfläche auftreten kann. Interessant ist, dass neben der Aktivität (dem Anrufer) auch diese andere Klasse benachrichtigt wird, wenn das Klickereignis auf der Schaltfläche auftritt.