Comment définir les rappels dans Android?

152

Lors de la dernière IO de Google, il y avait une présentation sur la mise en œuvre d'applications client reposantes. Malheureusement, ce n'était qu'une discussion de haut niveau sans code source de l'implémentation.

Dans ce diagramme, sur le chemin de retour, il existe différents rappels vers d'autres méthodes.

diapositive de présentation google io

Comment déclarer quelles sont ces méthodes?

Je comprends l'idée d'un rappel - un morceau de code qui est appelé après qu'un certain événement s'est produit, mais je ne sais pas comment l'implémenter. Jusqu'à présent, la seule façon dont j'ai implémenté les rappels a été de remplacer diverses méthodes (onActivityResult par exemple).

J'ai l'impression d'avoir une compréhension de base du modèle de conception, mais je n'arrête pas de me demander comment gérer le chemin de retour.

user409841
la source
3
Exactement ce dont vous avez besoin. Je cherchais la même chose et suis tombé sur ceci: javaworld.com/javaworld/javatips/jw-javatip10.html
Sid

Réponses:

218

Dans de nombreux cas, vous disposez d'une interface et transmettez un objet qui l'implémente. Les boîtes de dialogue, par exemple, ont OnClickListener.

Juste à titre d'exemple aléatoire:

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

J'ai probablement foiré la syntaxe de l'option 2. Il est tôt.

EboMike
la source
5
Un bon exemple pour maîtriser cette technique est de savoir comment un fragment doit communiquer avec un autre fragment via son activité partagée: developer.android.com/guide/components/...
Jordy
J'essaye de "implémenter" l'interface MyCallback dans une nouvelle activité qui ne réussit pas et le système m'oblige à modifier le chemin source dessus. Alors, comment effectuer un "rappel" d'une ancienne activité à une nouvelle activité?
Antoine Murion
3
Il dit que la variable de rappel dans la classe de travail est nulle pour moi
iYonatan
Quelqu'un pourrait-il donner l'équivalent kotlin?
Tooniis le
52

Quand quelque chose se passe à mon avis, je déclenche un événement que mon activité écoute:

// DÉCLARÉ EN VUE (PERSONNALISÉE)

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

// DÉCLARÉ EN ACTIVITÉ

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

Si vous voulez en savoir plus sur la communication (callbacks) entre les fragments, voir ici: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity

HGPB
la source
1
Ce tutoriel #CommunicatingWithActivity était génial. J'ai enfin compris comment utiliser les rappels après plusieurs essais.
Moises Jimenez
Très bonne réponse. Merci!
iYonatan
Simple et facile à comprendre. Merci!
Glenn J.Schworak
38

Pas besoin de définir une nouvelle interface lorsque vous pouvez utiliser un existant: android.os.Handler.Callback. Passez un objet de type Callback et invoquez des callbacks handleMessage(Message msg).

dragon
la source
Mais comment le faire?
majurageerthan
26

Exemple d'implémentation de la méthode de rappel à l'aide de l'interface.

Définissez l'interface, NewInterface.java .

package javaapplication1;

public interface NewInterface {
    void callback();
}

Créez une nouvelle classe, NewClass.java . Il appellera la méthode de rappel dans la 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, pour implémenter l'interface NewInterface - méthode callback (). Il créera et appellera l'objet NewClass. Ensuite, l'objet NewClass rappellera à son tour sa méthode 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");
    }

}
Amol Patil
la source
1
Jusqu'à présent, nous utilisions les interfaces pour le rappel, mais maintenant, square a développé une bibliothèque en tant que bus d'événements Otto. C'est vraiment plus rapide et utile.
Amol Patil
20

pour clarifier un peu la réponse de dragon (car il m'a fallu un certain temps pour savoir quoi faire Handler.Callback):

Handlerpeut être utilisé pour exécuter des rappels dans le thread actuel ou un autre thread, en le passant Messages. les Messagedonnées de retenue à utiliser à partir du rappel. a Handler.Callbackpeut être passé au constructeur de Handlerafin d'éviter d'étendre directement Handler. ainsi, pour exécuter du code via un rappel depuis le thread actuel:

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: je viens de me rendre compte qu'il existe un meilleur moyen d'obtenir le même résultat (moins le contrôle du moment exact où exécuter le rappel):

post(new Runnable() {
    @Override
    public void run() {
        <code to be executed during callback>
    }
});
MrGnu
la source
1
Votre message Runnable est à l'intérieur de la méthode handleMessage?
IgorGanapolsky
+1 pour la meilleure réponse. J'aime Callbackmieux la version parce que vous n'avez pas forcément accès aux données nécessaires Runnable.run()au moment où vous la construisez
Kirby
Remarque: "Tant que le constructeur de Message est public, la meilleure façon d'en obtenir un est d'appeler Message.obtain () ou l'une des méthodes Handler.obtainMessage (), qui les extraira d'un pool d'objets recyclés." - d'ici
jk7
10

Vous pouvez également utiliser LocalBroadcastà cette fin. Voici une petite quide

Créez un récepteur de diffusion:

   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
    }

Voici comment vous pouvez le déclencher

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

désenregistrer le destinataire dans onPause:

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