Как синхронизировать обработчики Android с разными интервалами?

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

  1. Продолжая мысль о Stephen C из его ответа , вы действительно не должны быть обеспокоены оптимизацией таких случаев, пока вы не узнаете, что это действительно узкое место в вашей заявке. Как сказал Дональд Кнут , «преждевременная оптимизация - это корень всего зла».
  2. Поскольку shmosel указал в комментарии, Collector, что выделяет HashMap с предопределенным размером, будет перераспределять, если указанный Collector используется в параллельном режиме. Поэтому Collector, который я предлагаю, не поддерживает параллельный сбор.

Сказав это, вы можете записать следующий общий Collector s:

public class ExtraCollectors {

    public static  Collector> toSizedMap(
            Function keyMapper, Function valueMapper, int size) {
        return toSequentialMap(
                () -> com.google.common.collect.Maps.newHashMapWithExpectedSize(size),
                keyMapper, valueMapper, Collector.Characteristics.UNORDERED
        );
    }

    public static > Collector toSequentialMap(
            Supplier mapSupplier, Function keyMapper,
            Function valueMapper, Collector.Characteristics... characteristics) {
        return Collector.of(
                mapSupplier,
                (map, element) -> map.merge(
                        keyMapper.apply(element), valueMapper.apply(element), ExtraCollectors::mergeUnsupported
                ),
                ExtraCollectors::combineUnsupported,
                characteristics
        );
    }

    private static  T mergeUnsupported(T valueA, T valueB) {
        throw new UnsupportedOperationException("This Collector does not support merging.");
    }

    private static  A combineUnsupported(A accumulatorA, A accumulatorB) {
        throw new UnsupportedOperationException("This Collector does not support parallel streams.");
    }
}

Обратите внимание, что я использовал Guava Maps.newHashMapWithExpectedSize , чтобы вы получили HashMap с нужным вам размером (примерно то, что Andreas объяснил в своем комментарии к вашему вопросу ). Если у вас нет зависимости от Guava (и вы не хотите этого делать), вы можете просто скопировать метод Maps.capacity на вашу кодовую базу.

Используя метод ExtraCollectors.toSizedMap(), определенный выше, ваш метод преобразования будет выглядеть следующим образом:

Map listToMap(List objs) {
    return objs.stream().collect(ExtraCollectors.toSizedMap(KeyedObject::getKey, obj -> obj, objs.size()));

}

Тем не менее, если вам действительно нужна максимальная производительность (по цене повторного использования), вы можете пропустить API Stream, и примените ваше решение 1, но с Maps.newHashMapWithExpectedSize, чтобы получить размер HashMap.

0
задан Jorge E. Hernández 18 January 2019 в 18:43
поделиться

3 ответа

Как насчет использования TimerTask и Timer для планирования повторного выполнения (каждые 5 секунд)? В зависимости от интервала вы выполняете либо задание, выполненное в настоящее время в handler1, либо задание в handler2, либо оба. Возможно, вы можете разбить эти задания на функции, которые вызываются из метода run TimerTask's. Это позволило бы заданию handler1 выполняться до задания handler2 синхронизированным образом в том же потоке.

0
ответ дан fejd 18 January 2019 в 18:43
поделиться

Поскольку handler2 выполняется чаще, чем handler1, вы можете использовать счетчик в handler2 для отслеживания того, когда следует запускать события, которые вы планируете инициировать в handler1.

handler2.postDelayed(new Runnable() {
    int count = 0;
    @Override
    public void run() {
        if (count == 0) {
            // fire handler1 events
        }
        count = (count+1) % 6;
    }
}, 5);
0
ответ дан Dino Tw 18 January 2019 в 18:43
поделиться

Чтобы убедиться, что handler1 всегда выполняется перед handler2 , вы можете использовать следующий подход:

Каждый раз, когда handler1 завершив то, что должен сделать, он [выдаст сигнал Service, в котором оба Handler работают, чтобы] немедленно запустить handler2 .

handler2 (или Service) будет разрешено запланировать повторное выполнение Runnable на следующие пять раундов. Вы можете использовать некоторый тип обратного отсчета, чтобы отслеживать оставшиеся раунды. Последний «независимо управляемый» раунд начнется примерно через 25 секунд после начального раунда. После этого раунда до handler1 может быть выдана следующая команда запуска для handler2 .

0
ответ дан 0X0nosugar 18 January 2019 в 18:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: