Como definir retornos de chamada no Android?

152

Durante o Google IO mais recente, houve uma apresentação sobre a implementação de aplicativos clientes tranqüilos. Infelizmente, foi apenas uma discussão de alto nível sem código-fonte da implementação.

Neste diagrama, no caminho de retorno, existem vários retornos de chamada diferentes para outros métodos.

slide de apresentação do google io

Como declaro quais são esses métodos?

Entendo a ideia de um retorno de chamada - um pedaço de código que é chamado após um determinado evento, mas não sei como implementá-lo. A única maneira de implementar os retornos de chamada até agora foi substituir vários métodos (onActivityResult, por exemplo).

Sinto que tenho um entendimento básico do padrão de design, mas continuo me enganando sobre como lidar com o caminho de retorno.

user409841
fonte
3
Exatamente o que você precisa. Eu estava procurando a mesma coisa e me deparei com isso: javaworld.com/javaworld/javatips/jw-javatip10.html
Sid

Respostas:

218

Em muitos casos, você tem uma interface e transmite um objeto que a implementa. Diálogos, por exemplo, têm o OnClickListener.

Apenas como um exemplo aleatório:

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

Eu provavelmente estraguei a sintaxe da opção 2. É cedo.

EboMike
fonte
5
Um bom exemplo para obter um controlo sobre esta técnica é como um fragmento deve se comunicar com outro fragmento através da sua atividade compartilhada: developer.android.com/guide/components/...
Jordy
Tento "implementar" a interface MyCallback em uma nova atividade que não é bem-sucedida e o sistema exige que eu edite o caminho de origem nela. Então, como eu realizaria o "callBack" de uma atividade antiga para uma nova?
Antoine Murion
3
Ele diz que variável callback na classe trabalhador é nulo para mim
iYonatan
Alguém poderia dar o equivalente kotlin?
Tooniis 26/01
52

Quando algo acontece em minha opinião, aciono um evento que minha atividade está ouvindo:

// DECLARADO NA 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 EM ATIVIDADE

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

Se você quiser saber mais sobre comunicação (retornos de chamada) entre fragmentos, consulte aqui: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity

HGPB
fonte
1
Esse tutorial #CommunicatingWithActivity foi incrível. Finalmente entendi como usar retornos de chamada após várias tentativas.
Moises Jimenez
Ótima resposta. Obrigado!
iYonatan 08/12/16
Simples e fácil de se entender. Obrigado!
precisa saber é o seguinte
38

Não há necessidade de definir uma nova interface quando você pode usar um já existente: android.os.Handler.Callback. Passe um objeto do tipo Chamada de retorno e invoque as chamadas de retorno handleMessage(Message msg).

Dragão
fonte
Mas como fazer isso?
majurageerthan
26

Exemplo para implementar o método de retorno de chamada usando a interface

Defina a interface, NewInterface.java .

pacote javaapplication1;

public interface NewInterface {
    void callback();
}

Crie uma nova classe, NewClass.java . Ele chamará o método de retorno de chamada na classe 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();
    }
}

A classe principal, JavaApplication1.java, para implementar a interface NewInterface - callback () method. Ele criará e chamará o objeto NewClass. Em seguida, o objeto NewClass retornará o método callback () por sua 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");
    }

}
Amol Patil
fonte
1
até agora, estávamos usando as interfaces para retorno de chamada, mas agora a square desenvolveu uma lib como Otto de barramento de eventos. É realmente mais rápido e útil.
Amol Patil #
20

para esclarecer um pouco a resposta do dragão (já que levei um tempo para descobrir o que fazer Handler.Callback):

Handlerpode ser usado para executar retornos de chamada no segmento atual ou outro, passando Messages. os Messagedados de retenção a serem usados ​​no retorno de chamada. um Handler.Callbackpode ser passado para o construtor de Handler, a fim de evitar estender o Handler diretamente. portanto, para executar algum código via retorno de chamada do thread atual:

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: acabei de perceber que existe uma maneira melhor de obter o mesmo resultado (menos controle sobre exatamente quando executar o retorno de chamada):

post(new Runnable() {
    @Override
    public void run() {
        <code to be executed during callback>
    }
});
MrGnu
fonte
1
Sua postagem Runnable está dentro do método handleMessage?
IgorGanapolsky 23/09
+1 para a melhor resposta. Eu gosto da Callbackversão melhor, porque você pode não necessariamente ter acesso aos dados necessários Runnable.run()no momento em que você construí-lo
Kirby
Nota: "Embora o construtor de Message seja público, a melhor maneira de obter uma dessas opções é chamar Message.obtain () ou um dos métodos Handler.obtainMessage (), que os retirará de um conjunto de objetos reciclados." - from here
jk7
10

Você também pode usar LocalBroadcastpara esse fim. Aqui está uma rápida

Crie um receptor de transmissão:

   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
    }

É assim que você pode acioná-lo

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

cancele o registro do receptor no onPause:

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