Как определить обратные вызовы в Android?

152

Во время самого последнего Google IO, была презентация о реализации спокойных клиентских приложений. К сожалению, это было только обсуждение на высоком уровне без исходного кода реализации.

На этой диаграмме на пути возврата есть различные обратные вызовы для других методов.

Слайд презентации Google io

Как мне объявить, что это за методы?

Я понимаю идею обратного вызова - кусок кода, который вызывается после определенного события, но я не знаю, как его реализовать. Единственный способ, которым я реализовал обратные вызовы, - это переопределение различных методов (например, onActivityResult).

Я чувствую, что у меня есть базовое понимание шаблона проектирования, но я продолжаю понимать, как обращаться с обратным путем.

user409841
источник
3
Именно то, что вам нужно. Я искал то же самое и наткнулся на это: javaworld.com/javaworld/javatips/jw-javatip10.html
Сид

Ответы:

218

Во многих случаях у вас есть интерфейс и вы передаете объект, который его реализует. Например, диалоги имеют OnClickListener.

Так же, как случайный пример:

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

Я, вероятно, испортил синтаксис в варианте 2. Это рано.

EboMike
источник
5
Хороший пример, чтобы овладеть этой техникой, - это как фрагмент должен общаться с другим фрагментом через общий доступ. Упражнение: developer.android.com/guide/components/…
Джорди
Я пытаюсь «внедрить» интерфейс MyCallback в новую операцию, которая не удалась, и система требует, чтобы я изменил исходный путь на нем. Итак, как бы я осуществил «обратный вызов» из старого действия в новое?
Антуан Мюрион
3
Он говорит, что переменная обратного вызова в рабочем классе для меня
пуста
Может ли кто-нибудь дать эквивалент котлина?
Tooniis
52

Когда что-то происходит, на мой взгляд, я запускаю событие, которое слушает моя деятельность:

// ОБЪЯВЛЕНО (ПОЛЬЗОВАТЕЛЬСКИЙ) ВИД

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

// ЗАЯВЛЕНО В ДЕЯТЕЛЬНОСТИ

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

Если вы хотите узнать больше о связи (обратные вызовы) между фрагментами, смотрите здесь: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity

HGPB
источник
1
Этот учебник #CommunicatingWithActivity был потрясающим. Наконец понял, как использовать обратные вызовы после нескольких испытаний.
Моизес Хименес
Отличный ответ. Спасибо!
iYonatan
Просто и легко понять. Спасибо!
Гленн Дж. Шворак
38

Нет необходимости , чтобы определить новый интерфейс , когда вы можете использовать существующий: android.os.Handler.Callback. Передайте объект типа Callback и вызовите функции обратного вызова handleMessage(Message msg).

Дракон
источник
но как это сделать?
27
26

Пример реализации метода обратного вызова с использованием интерфейса.

Определите интерфейс, NewInterface.java .

пакет javaapplication1;

public interface NewInterface {
    void callback();
}

Создайте новый класс, NewClass.java . Он вызовет метод обратного вызова в основном классе.

package javaapplication1;

public class NewClass {

    private NewInterface mainClass;

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

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

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

Основной класс JavaApplication1.java для реализации интерфейса NewInterface - метод callback (). Это создаст и вызовет объект NewClass. Затем объект NewClass будет вызывать свой метод 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
до сих пор мы использовали интерфейсы для обратного вызова, но теперь Square разработал lib как шину событий Otto. Это действительно быстрее и полезнее.
Амол Патил
20

чтобы немного разъяснить ответ дракона (так как мне потребовалось некоторое время, чтобы выяснить, что делать с Handler.Callback):

Handlerможет использоваться для выполнения обратных вызовов в текущем или другом потоке, передавая его Messages. Messageимеет данные , которые будут использоваться с обратного вызова. a Handler.Callbackможет быть передан в конструктор Handler, чтобы избежать непосредственного расширения Handler. таким образом, чтобы выполнить некоторый код через обратный вызов из текущего потока:

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

РЕДАКТИРОВАТЬ: только что понял, что есть лучший способ получить тот же результат (минус контроль точно, когда выполнять обратный вызов):

post(new Runnable() {
    @Override
    public void run() {
        <code to be executed during callback>
    }
});
MrGnu
источник
1
Ваш пост Runnable находится внутри метода handleMessage?
Игорь Ганапольский
+1 за лучший ответ. Мне больше нравится Callbackверсия, потому что вы не обязательно имеете доступ к данным, которые необходимы вам Runnable.run()в момент ее создания
Kirby
Примечание. «Хотя конструктор Message является общедоступным, лучший способ получить один из них - вызвать метод Message.obtain () или один из методов Handler.obtainMessage (), который извлечет их из пула переработанных объектов». - отсюда
jk7
10

Вы также можете использовать LocalBroadcastдля этой цели. Вот быстрый тест

Создать широковещательный приемник:

   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
    }

Вот как вы можете вызвать это

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

отменить регистрацию получателя в onPause:

protected void onPause() {
  super.onPause();
  LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
}
Рохит Мандивал
источник