RxJava:观察列表更改

时间:2019-05-29 14:20:26

标签: java rx-java

我有一个包含用户List<User> userList的列表。我想在列表更改时更新我的​​UI(从列表中删除用户或向列表添加用户)。我想在这种情况下我需要一个Observable<List<User>>。但是我不太了解如何在RxJava中实现这一点。

如果我使用Observable<String> observable = Observable.from(userList);,当我向userList中添加内容时会触发所有订阅者吗?

谢谢。

1 个答案:

答案 0 :(得分:0)

如果您查看subscribe运算符的内部,将会看到

@CheckReturnValue
    @SchedulerSupport(SchedulerSupport.NONE)
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {
        return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
    }

因此,我们看到subscribe得到Consumer<T>作为参数。让我们看看吧

/**
 * A functional interface (callback) that accepts a single value.
 * @param <T> the value type
 */
public interface Consumer<T> {
    /**
     * Consume the given value.
     * @param t the value
     * @throws Exception on error
     */
    void accept(T t) throws Exception;
}

因此,我们看到它只有一种方法:accept(T t)。接下来,我们可以得出一个结论:Observable订阅时,它正在等待来自消费者的事件OnNext。因此,要触发订阅,您需要在可观察对象中调用OnNext(T T)。但是,可观察的没有任何运算符显式地传递任何Consumer事件。但是Rx具有某种机制-Subjects

根据您的情况,最好使用 BehaviorSubject 。 Rx库还包含 AsyncSubject PublishSubject ReplaySubject 。关于它们,您可以在documentation

中阅读
  

当观察者订阅一个BehaviorSubject时,它首先发出源Observable最近发出的项目(如果尚未发出,则为种子/默认值),然后继续发出后来由该Observable发出的任何其他项目。源可观察的。

class Test {

    public static void main(String[] args) {
        // creating BehaviorSubject
        BehaviorSubject<String> subject = BehaviorSubject.create();

        // create Observable from subject
        Observable<String> observable = subject;

        // subscribe to OnNext event, and when the subject will emitting some 
        // events, observable will print a string, receiving from subject
        observable.subscribe(s -> System.out.print(s));

        // sending "hello" string to observable
        subject.onNext("hello");

        // sending " world!" string to observable
        subject.onNext(" world!");
    }

}

将输出输出:

  

你好,世界!

让我们用List研究您的问题。让我们定义用户类

class User {
    final long id;
    final String name;

    public User(long id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

现在,我们有几种方法可以观察用户列表。

第一种方法是每次修改时发送观察者列表。

class Test {

    public static void main(String[] args) {
        // define BehaviorSubject
        BehaviorSubject<List<User>> subject = BehaviorSubject.create();

        // define Observable from subject
        Observable<List<User>> observable = subject;

        // subscribe to OnNext event, and when the subject will emitting some
        // events, observable will print a string, receiving from subject
        observable.subscribe(s -> System.out.println(s.toString()));

        // create empty ArrayList with Users
        List<User> users = new ArrayList<>();

        // fill data
        users.add(new User(1, "John Doe"));
        users.add(new User(2, "Jane Doe"));

        // send list to observable
        subject.onNext(users);

        // let's add one more user to list
        users.add(new User(3, "Frank Doe"));

        // send updated list to observable
        subject.onNext(users);
    }

}

将打印输出:

  

[User {id = 1,name ='John Doe'},User {id = 2,name ='Jane Doe'}]   [User {id = 1,name ='John Doe'},User {id = 2,name ='Jane Doe'},User {id = 3,name ='Frank Doe'}]

第二种方法是对数据源进行反应式订阅。

class Test {

    public static void main(String[] args) {
        // create empty ArrayList with Users
        List<User> users = new ArrayList<>();

        // define BehaviorSubject
        BehaviorSubject<User> subject = BehaviorSubject.create();

        // define Observable from subject
        Observable<List<User>> observable = subject.map(user -> {
            users.add(user);
            return users;
        });

        // subscribe to OnNext event
        observable.subscribe(s -> System.out.println(s.toString()));

        // send first user to observable
        subject.onNext(new User(1, "John Doe"));

        // send second user to observable
        subject.onNext(new User(2, "Jane Doe"));

        // send third user to observable
        subject.onNext(new User(3, "Frank Doe"));
    }

}

希望,我订阅的所有详细信息将帮助您使用RxJava)) 只需将代码复制粘贴到您的IDE中并进行一些实验。玩得开心!

PS 关于ConnectableObservable,您可以在WIKI中阅读

  

Connectable Observable类似于普通的Observable,不同之处在于它在订阅时不会开始发出项目,而仅在调用其connect()方法时才开始发出项目。这样,您可以等待所有预期的订户订阅该Observable,然后该Observable开始发射项目。

PS 关于线程。您订阅和观察哪个线程非常重要。让我们看下一个修改的例子。

class Test {

    public static void main(String[] args) {
        // define BehaviorSubject
        BehaviorSubject<List<User>> subject = BehaviorSubject.create();

        // define Observable from subject
        Observable<List<User>> observable = subject;

        // subscribe to OnNext event, and when the subject will emitting some
        // events, observable will print a string, receiving from subject
        observable
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .subscribe(s -> System.out.println(s.toString()));

        // create empty ArrayList with Users
        List<User> users = new ArrayList<>();

        // fill data
        users.add(new User(1, "John Doe"));
        users.add(new User(2, "Jane Doe"));

        // send list to observable
        subject.onNext(users);

        // let's add one more user to list
        users.add(new User(3, "Frank Doe"));

        // send updated list to observable
        subject.onNext(users);

        // it's a hack, because if delete this string output will be empty
        while (true){}
    }

}

在继续阅读之前尝试猜测:将输出什么输出?

输出将是:

  

[User {id = 1,name ='John Doe'},User {id = 2,name ='Jane Doe'},User {id = 3,name ='Frank Doe'}]   [User {id = 1,name ='John Doe'},User {id = 2,name ='Jane Doe'},User {id = 3,name ='Frank Doe'}]

为什么?因为subscribeOnobserveOn发生在IO线程上。 subject.onNext(users);List<User>的对象从主线程发送到IO,第二次调用subject.onNext(users);时,用户列表已被修改。这是异步操作,应谨慎使用。 出于相同的原因,我们需要添加hack while (true){},因为Observable已订阅了IO线程,并且主线程中的所有工作都已完成并且应用程序调用系统退出。

例如,我要添加Thread.sleep并删除无限循环

class Test {

    public static void main(String[] args) {
        // define BehaviorSubject
        BehaviorSubject<List<User>> subject = BehaviorSubject.create();

        // define Observable from subject
        Observable<List<User>> observable = subject;

        // subscribe to OnNext event, and when the subject will emitting some
        // events, observable will print a string, receiving from subject
        observable
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .subscribe(s -> System.out.println(s.toString()));

        // create empty ArrayList with Users
        List<User> users = new ArrayList<>();

        // fill data
        users.add(new User(1, "John Doe"));
        users.add(new User(2, "Jane Doe"));

        // send list to observable
        subject.onNext(users);

        // let's suspend the thread, and wait when list will receive observable
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // let's add one more user to list
        users.add(new User(3, "Frank Doe"));

        // send updated list to observable
        subject.onNext(users);
    }

}

现在,将输出输出:

  

[User {id = 1,name ='John Doe'},User {id = 2,name ='Jane Doe'}]

一秒钟后将打印第二个字符串

  

[User {id = 1,name ='John Doe'},User {id = 2,name ='Jane Doe'},User {id = 3,name ='Frank Doe'}]

因此,Thread.sleep仅用于显示可观察对象和主题可以是异步的,以及它们在不同时间段内的行为。