Wie definiere ich Rückrufe in Android?

152

Während des letzten Google IO gab es eine Präsentation über die Implementierung erholsamer Clientanwendungen. Leider war es nur eine Diskussion auf hoher Ebene ohne Quellcode der Implementierung.

In diesem Diagramm gibt es auf dem Rückweg verschiedene Rückrufe zu anderen Methoden.

Google Io Präsentationsfolie

Wie erkläre ich, was diese Methoden sind?

Ich verstehe die Idee eines Rückrufs - ein Stück Code, der aufgerufen wird, nachdem ein bestimmtes Ereignis eingetreten ist, aber ich weiß nicht, wie ich es implementieren soll. Die einzige Möglichkeit, Rückrufe zu implementieren, bestand darin, verschiedene Methoden zu überschreiben (z. B. onActivityResult).

Ich habe das Gefühl, ein grundlegendes Verständnis für das Entwurfsmuster zu haben, aber ich werde immer wieder darüber informiert, wie ich mit dem Rückweg umgehen soll.

user409841
quelle
3
Genau das, was Sie brauchen. Ich suchte das Gleiche und stieß auf Folgendes
Sid

Antworten:

218

In vielen Fällen haben Sie eine Schnittstelle und geben ein Objekt weiter, das sie implementiert. Dialoge haben zum Beispiel den OnClickListener.

Nur als zufälliges Beispiel:

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

Ich habe wahrscheinlich die Syntax in Option 2 durcheinander gebracht. Es ist früh.

EboMike
quelle
5
Ein gutes Beispiel, um diese Technik in den Griff zu bekommen, ist, wie ein Fragment über seine gemeinsame Aktivität mit einem anderen Fragment kommunizieren sollte: developer.android.com/guide/components/…
Jordy
Ich versuche, die MyCallback-Schnittstelle in einer neuen Aktivität zu "implementieren", die nicht erfolgreich ist, und das System fordert mich auf, den Quellpfad darauf zu bearbeiten. Wie würde ich "callBack" von einer alten Aktivität zu einer neuen Aktivität ausführen?
Antoine Murion
3
Es heißt, dass die
Rückrufvariable
Könnte jemand das Kotlin-Äquivalent geben?
Tooniis
52

Wenn aus meiner Sicht etwas passiert, schalte ich ein Ereignis aus, auf das meine Aktivität wartet:

// IN (BENUTZERDEFINIERTER) ANSICHT ERKLÄRT

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

// IN AKTIVITÄT ERKLÄRT

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

Wenn Sie mehr über die Kommunikation (Rückrufe) zwischen Fragmenten erfahren möchten, lesen Sie hier: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity

HGPB
quelle
1
Das #CommunicatingWithActivity-Tutorial war fantastisch. Endlich verstanden, wie man Rückrufe nach mehreren Versuchen verwendet.
Moises Jimenez
Gute Antwort. Vielen Dank!
IYonatan
Einfach und leicht zu verstehen. Vielen Dank!
Glenn J. Schworak
38

Sie müssen keine neue Schnittstelle definieren, wenn Sie eine vorhandene verwenden können : android.os.Handler.Callback. Übergeben Sie ein Objekt vom Typ Rückruf und rufen Sie Rückrufe auf handleMessage(Message msg).

Drachen
quelle
aber wie geht das?
Majurageerthan
26

Beispiel für die Implementierung einer Rückrufmethode mithilfe der Schnittstelle.

Definieren Sie die Schnittstelle NewInterface.java .

Paket javaapplication1;

public interface NewInterface {
    void callback();
}

Erstellen Sie eine neue Klasse, NewClass.java . Es ruft die Rückrufmethode in der Hauptklasse auf.

package javaapplication1;

public class NewClass {

    private NewInterface mainClass;

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

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

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

Die Hauptklasse JavaApplication1.java zum Implementieren der Methode NewInterface - callback () der Schnittstelle. Es wird ein NewClass-Objekt erstellt und aufgerufen. Dann ruft das NewClass-Objekt nacheinander seine callback () -Methode zurück.

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
quelle
1
Bis jetzt haben wir die Schnittstellen für den Rückruf verwendet, aber jetzt hat square eine Bibliothek als Event-Bus Otto entwickelt. Es ist wirklich schneller und hilfreich.
Amol Patil
20

um ein wenig über die Antwort des Drachen zu klären (da ich eine Weile gebraucht habe, um herauszufinden, was ich damit anfangen soll Handler.Callback):

Handlerkann verwendet werden, um Rückrufe im aktuellen oder einem anderen Thread auszuführen, indem er Messages übergeben wird. Das Messageenthält Daten, die aus dem Rückruf verwendet werden sollen. a Handler.Callbackkann an den Konstruktor von übergeben werden, Handlerum zu vermeiden, dass Handler direkt erweitert wird. So führen Sie Code per Rückruf vom aktuellen Thread aus:

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

BEARBEITEN: Ich habe gerade festgestellt, dass es einen besseren Weg gibt, um das gleiche Ergebnis zu erzielen (abzüglich der Kontrolle, wann genau der Rückruf ausgeführt werden soll):

post(new Runnable() {
    @Override
    public void run() {
        <code to be executed during callback>
    }
});
MrGnu
quelle
1
Ihr ausführbarer Beitrag befindet sich in der handleMessage-Methode?
IgorGanapolsky
+1 für die beste Antwort. Ich mag die CallbackVersion besser, weil Sie möglicherweise nicht unbedingt Zugriff auf die Daten haben, die Runnable.run()zum Zeitpunkt der Erstellung benötigt werden
Kirby
Hinweis: "Während der Konstruktor von Message öffentlich ist, können Sie eine dieser Methoden am besten abrufen, indem Sie Message.obtain () oder eine der Handler.obtainMessage () -Methoden aufrufen, mit denen sie aus einem Pool recycelter Objekte abgerufen werden." - von hier
jk7
10

Sie können auch LocalBroadcastfür diesen Zweck verwenden. Hier ist eine kurze Frage

Erstellen Sie einen Rundfunkempfänger:

   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
    }

So können Sie es auslösen

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

Empfänger in onPause abmelden:

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