Bagaimana Mendefinisikan Callback di Android?


152

Selama Google IO terbaru, ada presentasi tentang penerapan aplikasi klien yang tenang. Sayangnya, itu hanya diskusi tingkat tinggi tanpa kode sumber implementasi.

Dalam diagram ini, di jalur pengembalian ada berbagai panggilan balik yang berbeda ke metode lain.

slide presentasi google io

Bagaimana saya menyatakan apa metode ini?

Saya mengerti ide panggilan balik - sepotong kode yang dipanggil setelah peristiwa tertentu terjadi, tetapi saya tidak tahu bagaimana cara mengimplementasikannya. Satu-satunya cara saya menerapkan panggilan balik sejauh ini telah mengesampingkan berbagai metode (misalnya onActivityResult).

Saya merasa seperti saya memiliki pemahaman dasar tentang pola desain, tapi saya terus tersandung bagaimana menangani jalur pengembalian.


3
Apa yang Anda butuhkan. Saya mencari hal yang sama dan menemukan ini: javaworld.com/javaworld/javatips/jw-javatip10.html
Sid

Jawaban:


218

Dalam banyak kasus, Anda memiliki antarmuka dan meneruskan objek yang mengimplementasikannya. Dialog misalnya memiliki OnClickListener.

Sama seperti contoh acak:

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

Saya mungkin mengacaukan sintaks di opsi 2. Ini lebih awal.


5
Contoh yang baik untuk memahami teknik ini adalah bagaimana sebuah fragmen harus berkomunikasi dengan fragmen lain melalui itu dibagikan Aktivitas: developer.android.com/guide/components/…
Jordy

Saya mencoba untuk "mengimplementasikan" antarmuka MyCallback dalam aktivitas baru yang tidak berhasil dan sistem mengharuskan saya untuk mengedit jalur sumber di atasnya. Jadi bagaimana saya melakukan "callBack" dari aktivitas lama ke aktivitas baru?
Antoine Murion

3
Dikatakan bahwa variabel callback di kelas pekerja adalah nol untuk saya
iYonatan

Bisakah seseorang memberikan yang setara dengan kotlin?
Tooniis

52

Ketika sesuatu terjadi dalam pandangan saya, saya memulai suatu peristiwa yang didengarkan aktivitas saya:

// DEKLARASI DALAM (KUSTOM)

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

// DEKLARASI DALAM AKTIVITAS

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

Jika Anda ingin tahu lebih banyak tentang komunikasi (panggilan balik) antar fragmen, lihat di sini: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity


1
Tutorial #CommunicatingWithActivity sangat mengagumkan. Akhirnya mengerti bagaimana menggunakan callback setelah beberapa percobaan.
Moises Jimenez

Jawaban yang bagus Terima kasih!
iYonatan

Sederhana dan mudah dimengerti. Terima kasih!
Glenn J. Schworak

38

Tidak perlu mendefinisikan antarmuka baru ketika Anda dapat menggunakan yang sudah ada: android.os.Handler.Callback. Lewati objek bertipe Callback, dan aktifkan callback handleMessage(Message msg).


tetapi bagaimana melakukannya?
majurageerthan

26

Contoh untuk menerapkan metode panggilan balik menggunakan antarmuka.

Tentukan antarmuka, NewInterface.java .

paket javaapplication1;

public interface NewInterface {
    void callback();
}

Buat kelas baru, NewClass.java . Ini akan memanggil metode panggilan balik di kelas utama.

package javaapplication1;

public class NewClass {

    private NewInterface mainClass;

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

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

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

Kelas utama, JavaApplication1.java, untuk mengimplementasikan antarmuka metode NewInterface - callback (). Ini akan membuat dan memanggil objek NewClass. Kemudian, objek NewClass akan memanggil metode callback () pada gilirannya.

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
sampai sekarang kami menggunakan antarmuka untuk callback tetapi sekarang square telah mengembangkan lib sebagai event-bus Otto. Benar-benar lebih cepat dan bermanfaat.
Amol Patil

20

untuk mengklarifikasi sedikit pada jawaban naga (karena butuh beberapa saat untuk mencari tahu apa yang harus dilakukan dengan Handler.Callback):

Handlerdapat digunakan untuk mengeksekusi callback di saat ini atau utas lainnya, dengan meneruskannya Messages. yang Messagememegang data yang akan digunakan dari callback. a Handler.Callbackdapat diteruskan ke konstruktor Handleruntuk menghindari perpanjangan Handler secara langsung. dengan demikian, untuk mengeksekusi beberapa kode melalui panggilan balik dari utas saat ini:

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: baru sadar ada cara yang lebih baik untuk mendapatkan hasil yang sama (kontrol minus kapan tepatnya melakukan panggilan balik):

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

1
Pos Runnable Anda ada di dalam metode handleMessage?
IgorGanapolsky

+1 untuk jawaban terbaik. Saya suka Callbackversi yang lebih baik karena Anda mungkin belum tentu memiliki akses ke data yang dibutuhkan Runnable.run()pada saat Anda membangunnya
Kirby

Catatan: "Walaupun konstruktor Pesan bersifat publik, cara terbaik untuk mendapatkannya adalah dengan memanggil Message.obtain () atau salah satu metode Handler.obtainMessage (), yang akan menarik mereka dari kumpulan objek yang didaur ulang." - dari sini
jk7

10

Anda juga dapat menggunakan LocalBroadcastuntuk tujuan ini. Berikut ini adalah kutipan cepat

Buat penerima siaran:

   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
    }

Ini adalah bagaimana Anda dapat memicunya

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

batalkan pendaftaran penerima di onPause:

protected void onPause() {
  super.onPause();
  LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.