Come definire i callback in Android?


152

Durante l'ultimo IO di Google, è stata presentata una presentazione sull'implementazione di applicazioni client riposanti. Sfortunatamente, è stata solo una discussione di alto livello senza codice sorgente dell'implementazione.

In questo diagramma, sul percorso di ritorno ci sono vari callback diversi ad altri metodi.

slide di presentazione di google io

Come dichiaro quali sono questi metodi?

Capisco l'idea di un callback - un pezzo di codice che viene chiamato dopo che si è verificato un determinato evento, ma non so come implementarlo. L'unico modo in cui ho implementato i callback finora è stato scavalcando vari metodi (ad esempio onActivityResult).

Mi sembra di avere una conoscenza di base del modello di progettazione, ma continuo a rimanere incastrato su come gestire il percorso di ritorno.


3
Esattamente quello che ti serve. Stavo cercando la stessa cosa e mi sono imbattuto in questo: javaworld.com/javaworld/javatips/jw-javatip10.html
Sid

Risposte:


218

In molti casi, hai un'interfaccia e passi lungo un oggetto che lo implementa. Le finestre di dialogo, ad esempio, hanno OnClickListener.

Proprio come un esempio casuale:

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

Probabilmente ho incasinato la sintassi nell'opzione 2. È presto.


5
Un buon esempio per comprendere questa tecnica è come un frammento dovrebbe comunicare con un altro frammento attraverso la sua attività condivisa: developer.android.com/guide/components/…
Jordy

Tento di "implementare" l'interfaccia MyCallback in una nuova attività che non ha esito positivo e il sistema mi richiede di modificare il percorso di origine su di esso. Quindi come potrei eseguire "callBack" da una vecchia attività a una nuova attività?
Antoine Murion,

3
Dice che la variabile di callback nella classe worker è nulla per me
iYonatan l'

Qualcuno potrebbe dare l'equivalente di kotlin?
Tooniis,

52

Quando succede qualcosa a mio avviso, spengo un evento che la mia attività è in ascolto:

// DICHIARATO IN (CUSTOM) VISTA

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

// DICHIARATO IN ATTIVITÀ

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

Se vuoi saperne di più sulla comunicazione (callback) tra i frammenti vedi qui: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity


1
Quel tutorial #CommunicatingWithActivity è stato fantastico. Finalmente ho capito come usare i callback dopo diverse prove.
Moises Jimenez,

Bella risposta. Grazie!
iYonatan,

Semplice e facile da capire Grazie!
Glenn J. Schworak,

38

Non c'è bisogno di definire una nuova interfaccia quando si può usare uno esistente: android.os.Handler.Callback. Passa un oggetto di tipo Callback e invoca callback handleMessage(Message msg).


ma come farlo?
majurageerthan,

26

Esempio per implementare il metodo di callback usando l'interfaccia.

Definire l'interfaccia, NewInterface.java .

pacchetto javaapplication1;

public interface NewInterface {
    void callback();
}

Crea una nuova classe, NewClass.java . Chiamerà il metodo di callback nella classe principale.

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 classe principale, JavaApplication1.java, per implementare l'interfaccia NewInterface - metodo callback (). Creerà e chiamerà l'oggetto NewClass. Quindi, l'oggetto NewClass richiamerà a sua volta il metodo callback ().

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
fino ad ora stavamo usando le interfacce per il callback ma ora square ha sviluppato una lib come bus eventi Otto. È davvero più veloce e utile.
Amol Patil,

20

per chiarire un po 'la risposta del drago (dal momento che mi ci è voluto un po' per capire cosa fare con Handler.Callback):

Handlerpuò essere utilizzato per eseguire callback nel thread corrente o in un altro, passandolo Message. i Messagedati di conservazione da utilizzare dal callback. a Handler.Callbackpuò essere passato al costruttore di Handlerper evitare di estendere direttamente l'handler. quindi, per eseguire un po 'di codice tramite callback dal thread corrente:

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: appena realizzato c'è un modo migliore per ottenere lo stesso risultato (meno il controllo di esattamente quando eseguire il callback):

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

1
Il tuo post eseguibile è all'interno del metodo handleMessage?
IgorGanapolsky,

+1 per la migliore risposta. Mi piace di più la Callbackversione perché potresti non avere necessariamente accesso ai dati necessari Runnable.run()nel momento in cui la costruisci
Kirby,

Nota: "Mentre il costruttore di Message è pubblico, il modo migliore per ottenere uno di questi è chiamare Message.obtain () o uno dei metodi Handler.obtainMessage (), che li estrarrà da un pool di oggetti riciclati." - da qui
jk7

10

È inoltre possibile utilizzare LocalBroadcastper questo scopo. Ecco una breve guida

Creare un ricevitore di trasmissione:

   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
    }

Ecco come attivarlo

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

unRegistra ricevitore in onPause:

protected void onPause() {
  super.onPause();
  LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.