Як визначити зворотні виклики в Android?


152

Під час останньої роботи з Google IO відбулася презентація щодо впровадження спокійних клієнтських програм. На жаль, це була лише дискусія на високому рівні, без вихідного коду реалізації.

На цій діаграмі на шляху повернення є різні різні зворотні дзвінки до інших методів.

слайд презентації google io

Як я декларую, що це за методи?

Я розумію ідею зворотного дзвінка - фрагмент коду, який викликається після певної події, але я не знаю, як його реалізувати. Єдиним способом, яким я реалізував зворотні виклики до цих пір, було переосмислення різних методів (наприклад, onActivityResult).

Я відчуваю, що в мене є основне розуміння структури дизайну, але я продовжую працювати, як впоратися зі зворотним шляхом.


3
Саме те, що вам потрібно. Я шукав те ж саме , і наткнувся на це: javaworld.com/javaworld/javatips/jw-javatip10.html
Sid

Відповіді:


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. Рано.


5
Хороший приклад, щоб зрозуміти цю техніку - це те, як фрагмент повинен спілкуватися з іншим фрагментом через його спільну активність: developer.android.com/guide/components/…
Jordy

Я намагаюся "реалізувати" інтерфейс MyCallback в новій діяльності, яка не є успішною, і система вимагає від мене редагувати вихідний шлях на ньому. Тож як я можу здійснювати "callBack" зі старого заняття до нового?
Антуан Муріон

3
У ньому йдеться про те, що змінна зворотного виклику в класі робітників для мене є нульовою
iYonatan

Може хтось може дати еквівалент котліну?
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


1
Цей підручник #CommunicatingWithActivity був приголомшливим. Нарешті зрозумів, як використовувати зворотні дзвінки після кількох випробувань.
Мойсей Хіменес

Чудова відповідь. Дякую!
iYonatan

Простий і легкий для розуміння. Дякую!
Glenn J. Schworak

38

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


але як це зробити?
majurageerthan

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 - метод зворотного виклику (). Він створить і викличе об’єкт 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
до цих пір ми використовували інтерфейси для зворотного дзвінка, але тепер у квадраті розроблено ліб як шина подій Otto. Це дійсно швидше і корисніше.
Amol Patil

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

EDIT: щойно зрозумів, що є кращий спосіб отримати той же результат (мінус контроль того, коли саме виконати зворотний виклик):

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

1
Ваша посада Runnable знаходиться в методі handleMessage?
ІгорГанапольський

+1 за найкращу відповідь. Мені подобається Callbackверсія краще, тому що, можливо, вам не обов’язково мати доступ до даних, необхідних Runnable.run()під час її створення
Кірбі

Примітка: "Хоча конструктор 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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.