Android: выполнить запуск в интервале с лямбда - PullRequest
1 голос
/ 02 апреля 2019

Способ выполнения кода каждые X миллис в Android заключается в следующем шаблоне:

    void test(Handler handler) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                // Do something

                // Do it every 200ms
                handler.postDelayed(this, 200);
            }
        });
    }

Однако я начал изменять код для использования лямбда-выражений, когда это возможно.Изменение этого шаблона на лямбда имеет одну проблему: this внутри лямбды ссылается на внешний класс, поэтому его нельзя использовать в postDelayed(...).

Чтобы заставить его работать, я должен сохранить ссылку налямбдаОднако эта ссылка не может быть в локальной переменной.Это означает поиск значимого имени для этого лямбда-запускаемого и сохранение его как члена класса:

    private Runnable intervalRunnable;

    ...

    void testWithLambda() {
        this.intervalRunnable = () -> {
            // Do something

            // Do it every 200ms
            handler.postDelayed(intervalRunnable, 200);
        };
        handler.post(intervalRunnable);
    }

Таким образом, код более «современный», но, возможно, более уродливый и менее обслуживаемый.

Есть ли другой способ решить эту проблему?Я люблю лямбды, но я бы предпочел не хранить эти ссылки на уровне класса.Между этими опциями я предпочитаю придерживаться анонимного шаблона класса.

1 Ответ

1 голос
/ 02 апреля 2019

В спецификации языка сказано, что:

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

Который я читал как в основном высказывание "если вам нужна рекурсивная лямбда, не используйтелямбда. "

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

Вы можете попытаться скрыть тот факт, что вы используете ссылку на метод:

Handler handler = new Handler();

Runnable everyXMillis(Runnable inner, int ms) {
    return () -> {
        inner.run();
        handler.postDelayed(everyXMillis(inner, ms), ms);
    };
}

void testWithMethodReference() {
    handler.post(everyXMillis(() -> {
        // do something
    }, 200));
}

... но ... чёрт!Если вы обеспокоены наличием уродливого и не поддерживаемого кода, вам, пожалуй, лучше использовать более многословный анонимный Runnable.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...