159

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.

Haywire
  • 858
  • 3
  • 14
  • 30
user409841
  • 1,637
  • 2
  • 11
  • 5
  • 3
    Exactly what you need. I was looking for the same thing and came across this: http://www.javaworld.com/javaworld/javatips/jw-javatip10.html – Sid Sep 30 '10 at 20:08

7 Answers7

231

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.

EboMike
  • 76,846
  • 14
  • 164
  • 167
  • 6
    A good example to get a grip on this technique is how a fragment should communicate with another fragment through it's shared Activity: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity – Jordy Dec 06 '13 at 12:31
  • I attempt to "implements" MyCallback interface in a new activity which is not successful and the system requires me to edit the source path on it. So how would i carry out "callBack" from an old activity to a new activity? – Antoine Murion Apr 20 '15 at 08:41
  • 3
    It says that callback variable in the worker class is null for me – iYonatan Dec 08 '16 at 15:58
  • 1
    Could someone give the kotlin equivalent? – Tooniis Jan 26 '20 at 04:58
  • The most concise and understandable example one could wish for! – mdev Nov 11 '22 at 20:11
55

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

HGPB
  • 4,346
  • 8
  • 50
  • 86
39

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

dragon
  • 1,747
  • 15
  • 18
29

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

}
Amol Patil
  • 491
  • 4
  • 9
  • 1
    till now we were using the interfaces for callback but now square has develop a lib as event-bus Otto .Its really faster and helpful. – Amol Patil Nov 06 '15 at 08:26
22

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>
    }
});
MrGnu
  • 286
  • 2
  • 5
  • 1
    Your Runnable post is inside handleMessage method? – IgorGanapolsky Sep 23 '13 at 03:55
  • +1 for the best answer. I like the `Callback` version better because you may not necessarily have access to the data needed by `Runnable.run()` at the time that you construct it – Kirby Jun 30 '16 at 16:57
  • Note: "While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects." -- [from here](https://developer.android.com/reference/android/os/Message.html) – jk7 May 31 '17 at 18:04
11

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);
}
Arpit Patel
  • 7,212
  • 5
  • 56
  • 67
Rohit Mandiwal
  • 10,258
  • 5
  • 70
  • 83
1

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()
}
Mohammad
  • 11
  • 2