¿Cómo definir devoluciones de llamada en Android?


152

Durante el más reciente Google IO, hubo una presentación sobre la implementación de aplicaciones cliente tranquilas. Desafortunadamente, fue solo una discusión de alto nivel sin código fuente de la implementación.

En este diagrama, en la ruta de retorno hay varias devoluciones de llamada diferentes a otros métodos.

diapositiva de presentación de google io

¿Cómo declaro cuáles son estos métodos?

Entiendo la idea de una devolución de llamada: un fragmento de código que se llama después de que cierto evento ha sucedido, pero no sé cómo implementarlo. La única forma en que he implementado devoluciones de llamada hasta ahora ha sido anular varios métodos (en OnActivityResult, por ejemplo).

Siento que tengo una comprensión básica del patrón de diseño, pero sigo tropezando con la forma de manejar el camino de regreso.


3
Exactamente lo que necesitas. Estaba buscando lo mismo y encontré esto: javaworld.com/javaworld/javatips/jw-javatip10.html
Sid

Respuestas:


218

En muchos casos, tiene una interfaz y pasa un objeto que la implementa. Los cuadros de diálogo, por ejemplo, tienen OnClickListener.

Solo como un ejemplo aleatorio:

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

Probablemente estropeé la sintaxis en la opción 2. Es temprano.


55
Un buen ejemplo para comprender esta técnica es cómo un fragmento debe comunicarse con otro fragmento a través de su actividad compartida: developer.android.com/guide/components/…
Jordy

Intento "implementar" la interfaz MyCallback en una nueva actividad que no tiene éxito y el sistema requiere que edite la ruta de origen en ella. Entonces, ¿cómo realizaría "callBack" de una actividad anterior a una nueva?
Antoine Murion

3
Dice que la variable de devolución de llamada en la clase trabajadora es nula para mí
iYonatan

¿Alguien podría dar el equivalente de Kotlin?
Tooniis

52

Cuando algo sucede desde mi punto de vista, enciendo un evento que mi actividad está escuchando:

// DECLARADO EN VISTA (PERSONALIZADA)

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

// DECLARADO EN ACTIVIDAD

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

Si desea obtener más información sobre la comunicación (devoluciones de llamada) entre fragmentos, consulte aquí: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity


1
Ese tutorial #CommunicatingWithActivity fue increíble. Finalmente entendí cómo usar las devoluciones de llamada después de varios ensayos.
Moises Jimenez

Gran respuesta. ¡Gracias!
iYonatan

Simple y fácil de entender. ¡Gracias!
Glenn J. Schworak

38

No hay necesidad de definir una nueva interfaz cuando se puede usar una existente: android.os.Handler.Callback. Pase un objeto de tipo Devolución de llamada e invoque la devolución de llamada handleMessage(Message msg).


¿Pero como hacerlo?
Majurageerthan

26

Ejemplo para implementar el método de devolución de llamada utilizando la interfaz.

Defina la interfaz, NewInterface.java .

paquete javaapplication1;

public interface NewInterface {
    void callback();
}

Crea una nueva clase, NewClass.java . Llamará al método de devolución de llamada en la clase principal.

package javaapplication1;

public class NewClass {

    private NewInterface mainClass;

    public NewClass(NewInterface mClass){
        mainClass = mClass;
    }

    public void calledFromMain(){
        //Do somthing...

        //call back main
        mainClass.callback();
    }
}

La clase principal, JavaApplication1.java, para implementar la interfaz NewInterface - método callback (). Creará y llamará al objeto NewClass. Luego, el objeto NewClass devolverá su método callback () a su vez.

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

}

1
hasta ahora estábamos usando las interfaces para devolución de llamada, pero ahora square ha desarrollado una lib como event-bus Otto. Es realmente más rápido y útil.
Amol Patil

20

para aclarar un poco la respuesta del dragón (ya que me tomó un tiempo descubrir qué hacer con Handler.Callback):

Handlerse puede usar para ejecutar devoluciones de llamada en el hilo actual u otro, pasándolo Messages. los Messagedatos retenidos que se utilizarán desde la devolución de llamada. a Handler.Callbackse puede pasar al constructor de Handlerpara evitar extender Handler directamente. por lo tanto, para ejecutar algún código mediante devolución de llamada desde el hilo actual:

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

EDITAR: acabo de darme cuenta de que hay una mejor manera de obtener el mismo resultado (menos el control de exactamente cuándo ejecutar la devolución de llamada):

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

1
¿Tu publicación Runnable está dentro del método handleMessage?
IgorGanapolsky

+1 para la mejor respuesta. Me gusta más la Callbackversión porque no necesariamente tienes acceso a los datos necesarios Runnable.run()en el momento en que la construyes
Kirby

Nota: "Si bien el constructor de Message es público, la mejor manera de obtener uno de estos es llamar a Message.obtain () o uno de los métodos Handler.obtainMessage (), que los extraerá de un grupo de objetos reciclados". - desde aquí
jk7

10

También puede usar LocalBroadcastpara este propósito. Aquí hay un resumen rápido

Crear un receptor de difusión:

   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
    }

Así es como puedes activarlo

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

cancelar el registro del receptor en onPause:

protected void onPause() {
  super.onPause();
  LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.