Какой хороший вариант использования .defer () помимо system.currenttimemillis ()

У меня такой код:

Single<Player> createPlayerSingle() {
    Integer playerId = Random.nextInteger();
    return playersDao.createSingle(id);
}

Мне сказали, что я должен добавить Single.defer().

Single<Player> createPlayerSingle() {
    return Single.defer(() -> {
        Integer playerId = Random.nextInteger();
        return playersDao.createSingle(id);
    }
}

Идея заключалась в том, что если мы создадим еще одну подписку на createPlayerSingle(), мы не будем генерировать новый идентификатор (в основном мы повторно будем использовать старый).

Я не могу понять, почему это так. Должны ли мы тогда добавить defer к каждой функции, которая начинается с некоторого блока кода синхронизации?

Single<T> methodSingle() {
    return Single.defer(() -> {
        Integer id = Random.nextInteger(); // sync block of code
        ....
        return dao.createSingle(id);
    });
}

Я понимаю, что делает defer (он выполняет лямбда-выражение для каждого подписчика, например, если мы поместим System.currentTimeMillis() внутри лямбда-выражения, мы получим 2 разных значения для 2 подписок вместо одного значения, если мы используем .just или .fromCallable вместо .defer) .

Должны ли мы помещать сюда defer, когда мы берем свойство из аргумента? Для меня это не имеет смысла (даже если мы второй раз подпишемся на результат этого метода, мы вызовем его с некоторыми аргументами).

Single<T> methodSingle(Object object) {
        return Single.defer(() -> {
            Integer id = object.id; // sync block of code
            ....
            return dao.createSingleFrom(id);
        });
    }
2
0
456
2

Ответы 2

Когда вы пишете метод, который возвращает Single (или любой другой тип потока RxJava), вы возвращаете то, на что можно подписаться много раз, возможно, одновременно.

Defer - чрезвычайно мощный (но простой) оператор, который позволяет вам определять состояние за подписку. Например, если вам нужно особое поведение для первого выброса:

Observable<Integer> numbers = Observable.just(1, 2, 3);
Observable<Integer> numbers2 = 
    Observable.defer(() -> {
        boolean[] first = new boolean[] {true};
        return numbers.doOnNext(x -> {
            if (first[0]) {
                System.out.println("first=" + x);
                first[0] = false;
            } else {
                System.out.println(x);
            }
        });
    });
numbers2.subscribe();
numbers2.subscribe();

производит

first=1
2
3
first=1
2
3

Повторите этот код:

Single<T> methodSingle(Object object) {
    return Single.defer(() -> {
        Integer id = object.id; // sync block of code
        ....
        return dao.createSingleFrom(id);
    });
}

Если object неизменяемый, то это бессмысленно, и вы могли бы не использовать defer, как вы подозреваете.

Каждый раз, когда я чувствую необходимость возиться с .create (), я понимаю, что с .defer () это просто. Подготовительный код .defer () обычно запускает запросы и передает результат в Observable.just ().

Другие вопросы по теме