How to Define Callbacks in Android?

AndroidCallback

Android Problem Overview


During the most recent Google IO, there was a presentation about implementing restful client applications. Unfortunately, it was only a high level discussion with no source code of the implementation.

In this diagram, on the return path there are various different callbacks to other methods.

google io presentation slide

How do I declare what these methods are?

I understand the idea of a callback - a piece of code that gets called after a certain event has happened, but I don't know how to implement it. The only way I've implemented callbacks so far have been overriding various methods (onActivityResult for example).

I feel like I have a basic understanding of the design pattern, but I keep on getting tripped up on how to handle the return path.

Android Solutions


Solution 1 - Android

In many cases, you have an interface and pass along an object that implements it. Dialogs for example have the OnClickListener.

Just as a random example:

// The callback interface
interface MyCallback {
    void callbackCall();
}

// The class that takes the callback
class Worker {
   MyCallback callback;

   void onEvent() {
      callback.callbackCall();
   }
}

// Option 1:

class Callback implements MyCallback {
   void callbackCall() {
      // callback code goes here
   }
}

worker.callback = new Callback();

// Option 2:

worker.callback = new MyCallback() {

   void callbackCall() {
      // callback code goes here
   }
};

I probably messed up the syntax in option 2. It's early.

Solution 2 - Android

When something happens in my view I fire off an event that my activity is listening for:

// DECLARED IN (CUSTOM) VIEW

    private OnScoreSavedListener onScoreSavedListener;
	public interface OnScoreSavedListener {
	    public void onScoreSaved();
	}
	// ALLOWS YOU TO SET LISTENER && INVOKE THE OVERIDING METHOD 
    // FROM WITHIN ACTIVITY
	public void setOnScoreSavedListener(OnScoreSavedListener listener) {
		onScoreSavedListener = listener;
	}

// DECLARED IN ACTIVITY

    MyCustomView slider = (MyCustomView) view.findViewById(R.id.slider)
    slider.setOnScoreSavedListener(new OnScoreSavedListener() {
	    @Override
	    public void onScoreSaved() {
            Log.v("","EVENT FIRED");
	    }
    });

If you want to know more about communication (callbacks) between fragments see here: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity

Solution 3 - Android

No need to define a new interface when you can use an existing one: android.os.Handler.Callback. Pass an object of type Callback, and invoke callback's handleMessage(Message msg).

Solution 4 - Android

Example to implement callback method using interface.

Define the interface, NewInterface.java.

package javaapplication1;

public interface NewInterface {
    void callback();
}

Create a new class, NewClass.java. It will call the callback method in main class.

package javaapplication1;
 
public class NewClass {
     
    private NewInterface mainClass;
     
    public NewClass(NewInterface mClass){
        mainClass = mClass;
    }
     
    public void calledFromMain(){
        //Do somthing...
         
        //call back main
        mainClass.callback();
    }
}

The main class, JavaApplication1.java, to implement the interface NewInterface - callback() method. It will create and call NewClass object. Then, the NewClass object will callback it's callback() method in turn.

package javaapplication1;
public class JavaApplication1 implements NewInterface{
     
    NewClass newClass;
 
    public static void main(String[] args) {
         
        System.out.println("test...");
         
        JavaApplication1 myApplication = new JavaApplication1();
        myApplication.doSomething();
 
    }
     
    private void doSomething(){
        newClass = new NewClass(this);
        newClass.calledFromMain();
    }
 
    @Override
    public void callback() {
        System.out.println("callback");
    }
 
}

Solution 5 - Android

to clarify a bit on dragon's answer (since it took me a while to figure out what to do with Handler.Callback):

Handler can be used to execute callbacks in the current or another thread, by passing it Messages. the Message holds data to be used from the callback. a Handler.Callback can be passed to the constructor of Handler in order to avoid extending Handler directly. thus, to execute some code via callback from the current thread:

Message message = new Message();
<set data to be passed to callback - eg message.obj, message.arg1 etc - here>

Callback callback = new Callback() {
    public boolean handleMessage(Message msg) {
        <code to be executed during callback>
    }
};

Handler handler = new Handler(callback);
handler.sendMessage(message);

EDIT: just realized there's a better way to get the same result (minus control of exactly when to execute the callback):

post(new Runnable() {
    @Override
    public void run() {
        <code to be executed during callback>
    }
});

Solution 6 - Android

You can also use LocalBroadcast for this purpose. Here is a quick guide

Create a broadcast receiver:

   LocalBroadcastManager.getInstance(this).registerReceiver(
            mMessageReceiver, new IntentFilter("speedExceeded"));

private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Double currentSpeed = intent.getDoubleExtra("currentSpeed", 20);
        Double currentLatitude = intent.getDoubleExtra("latitude", 0);
        Double currentLongitude = intent.getDoubleExtra("longitude", 0);
        //  ... react to local broadcast message
    }

This is how you can trigger it

Intent intent = new Intent("speedExceeded");
intent.putExtra("currentSpeed", currentSpeed);
intent.putExtra("latitude", latitude);
intent.putExtra("longitude", longitude);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

unRegister receiver in onPause:

protected void onPause() {
  super.onPause();
  LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
}

Solution 7 - Android

asume the main function is the activity that is triggering the event:

fun main() {

val worker = Worker()

worker.setOnCallListener(
	object: OnCallListener {
        override fun onCall() {
            // here we define what should happen
            // when the event accures
            print("event happend")
        }
    }
)

// most events will be called from Android system itself
// but in our case we have to call it manually
worker.listener.onCall()
}

the Worker class has an instance of Type OnCallListener interface and a method to set its value:

class Worker() {
    lateinit var listener: OnCallListener

    fun setOnCallListener(listener: OnCallListener) {
	    this.listener = listener
    }
}

and the OnCallListener interface looks like this:

interface OnCallListener {
    fun onCall()
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser409841View Question on Stackoverflow
Solution 1 - AndroidEboMikeView Answer on Stackoverflow
Solution 2 - AndroidHGPBView Answer on Stackoverflow
Solution 3 - AndroiddragonView Answer on Stackoverflow
Solution 4 - AndroidAmol PatilView Answer on Stackoverflow
Solution 5 - AndroidMrGnuView Answer on Stackoverflow
Solution 6 - AndroidAshishView Answer on Stackoverflow
Solution 7 - AndroidMohammadView Answer on Stackoverflow