SOM-ITSOLUTIONS

C/Java/OOPS

Callback using Function Pointer (in C), interface (in Java) and EventListener pattern

SOMENATH MUKHOPADHYAY

som-itsolutions

#A2 1/13 South Purbachal Hospital Road Kolkata 700078 Mob: +91 9748185282

Email: som@som-itsolutions.com / som.mukhopadhyay@gmail.com

Website: http://www.som-itsolutions.com/

Blog: www.som-itsolutions.blogspot.com


“In computer programming, a callback is a reference to executable code, or a piece of executable code, that is passed as an argument to other code. This allows a lower-level software layer to call a subroutine (or function) defined in a higher-level layer.” - Wikipedia

Callback in C using Function Pointer

In C, callback is implemented using Function Pointer. Function Pointer - as the name suggests, is a pointer to a function.

For example, int (*ptrFunc) ();

Here, ptrFunc is a pointer to a function that takes no arguments and returns an integer. DO NOT forget to put in the parenthesis, otherwise the compiler will assume that ptrFunc is a normal function name, which takes nothing and returns a pointer to an integer.

Here is some code to demonstrate the function pointer.

#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;

}

Now let us try to understand the concept of Callback in  C using function pointer.

The complete program has three files: callback.c, reg_callback.h and  reg_callback.c.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

/* 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;

}

1

2

3

/* reg_callback.h */

typedef void (*callback)(void);

void register_callback(callback ptr_reg_callback);

1

2

3

4

5

6

7

8

9

10

11

/* 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)();                                      

}

If we run this program, the output will be

This is a program demonstrating function callback

inside register_callback

inside my_callback

back inside main program

The higher layer function calls a lower layer function as a normal call and the callback mechanism allows the lower layer function to call the higher layer function through a pointer to a callback function.

Callback in Java using Interface

Let me demonstrate it through an example:

The CallBack Interface

public interface Callback

{

    public void notify(Result result);

}

 The Caller or the Higher Level Class

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

}

}

The Callee or the Lower Layer Function

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

}

}

Callback using EventListener/Observer pattern

Let me explain it through an example.

The Events Interface

public interface Events {

public void clickEvent();

public void longClickEvent();

}

Class 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);
        
}
}

Class Button

public class Button extends Widget{

private String mButtonText;

public Button (){

}

public String getButtonText() {

return mButtonText;

}

public void setButtonText(String buttonText) {

this.mButtonText = buttonText;

}

}

Class Checkbox

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;

}

}

Activity Class

package 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();
   
}   
}

Other Class

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...");

}

}

Main Class

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);

}

}

As you can see from the above code, that we have an interface called events which basically lists all the events that may happen for our application. The Widget class is the base class for all the UI components like Button, Checkbox. These UI components are the objects that actually receive the events from the framework code. Widget class implements the Events interface and also it has two nested interfaces namely OnClickEventListener & OnLongClickEventListener

These two interfaces are responsible for listening to events that may occur on the Widget derived UI components like Button or Checkbox. So if we compare this example with the earlier Callback example using Java Interface, these two interfaces work as the Callback interface. So the higher level code (Here Activity) implements these two interfaces. And whenever an event occurs to a widget, the higher level code (or the method of these interfaces implemented in the higher level code, which is here Activity) will be called.

Now let me discuss the basic difference between Callback and Eventlistener pattern. As we have mentioned that using Callback, the Callee can notify only a single Caller. But in the case of EventListener pattern, any other part or class of the Application can register for the events that may occur on the Button or Checkbox. The example of this kind of class is the OtherClass. If you see the code of the OtherClass, you will find that it has registered itself as a listener to the ClickEvent that may occur in the Button defined in the Activity. Interesting part is that, besides the Activity ( the Caller), this OtherClass will also be notified whenever the click event occurs on the Button.