将Observable与反馈合并,将Observable与自身合并

时间:2017-02-04 04:39:08

标签: rx-java system.reactive reactive-programming rx-android

我需要创建Observable,它将从不同的源(其他Observables)收集信息,并且每个源都会对事件值产生影响,但是,该值是基于以前的值(状态机的种类)构建的。 / p>

我们有带有int值和操作码的消息:

class Message{
    Integer value;
    String operation;

    public Message(Integer value, String operation) {
        this.value = value;
        this.operation = operation;
    }
}

这些值的一些来源,使用init值:

Observable<Message> dynamicMessage = Observable.just(new Message(1, "+"));

现在有事件来源。这些源将根据其发出值,并根据dynamicMessage的previos值显示新的dynamicMessage值。实际上它的事件类型是:

class Changer1 {
    String operation;

    public Changer1(String operation) {
        this.operation = operation;
    }
}


class Changer2 {
    Integer value;

    public Changer2(Integer value) {
        this.value = value;
    }
}

Changer1可以更改操作。 Changer2对变化的价值有反应。

以及这些价值观的来源:

static Observable<Changer1> changers1 = Observable.just(new Changer1("-"))
        .delay(1, TimeUnit.SECONDS).concatWith(Observable.just(new Changer1("+"))
                .delay(2, TimeUnit.SECONDS));


static Observable<Changer2> changers2 = Observable.just(new Changer2(2))
        .delay(2, TimeUnit.SECONDS).concatWith(Observable.just(new Changer2(2))
                .delay(2, TimeUnit.SECONDS));

现在我需要更改dynamicMessage Observable并接受来自转换器的消息。这是一张图: state machine

另外我尝试编写一个程序,我是如何看到解决方案的,但是它与OutOfMemoryException挂起,在第一个值之后是rigth:
消息{值= 1,操作=&#39; +&#39;}
列表:

import rx.Observable;
import rx.functions.Action1;
import rx.functions.Func1;

public class RxDilemma {


static class Message{
    Integer value;
    String operation;

    public Message(Integer value, String operation) {
        this.value = value;
        this.operation = operation;
    }

    @Override
    public String toString() {
        return "Message{" +
                "value=" + value +
                ", operation='" + operation + '\'' +
                '}';
    }
}

static class Changer1 {
    String operation;

    public Changer1(String operation) {
        this.operation = operation;
    }

    @Override
    public String toString() {
        return "Changer1{" +
                "operation='" + operation + '\'' +
                '}';
    }
}


static class Changer2 {
    Integer value;

    public Changer2(Integer value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Changer2{" +
                "value=" + value +
                '}';
    }
}





static Observable<Changer1> changers1 = Observable.just(new Changer1("-"))
        .delay(1, TimeUnit.SECONDS).concatWith(Observable.just(new Changer1("+"))
                .delay(2, TimeUnit.SECONDS));


static Observable<Changer2> changers2 = Observable.just(new Changer2(2))
        .delay(2, TimeUnit.SECONDS).concatWith(Observable.just(new Changer2(2))
                .delay(2, TimeUnit.SECONDS));


static Observable<Message> dynamicMessage = Observable.just(new Message(1, "+")).mergeWith(changers1.flatMap(new Func1<Changer1, Observable<Message>>() {
    @Override
    public Observable<Message> call(final Changer1 changer) {
        return dynamicMessage.last().map(new Func1<Message, Message>() {
            @Override
            public Message call(Message message) {
                message.operation = changer.operation;
                return message;
            }
        });
    }
})).mergeWith(changers2.flatMap(new Func1<Changer2, Observable<Message>>() {
    @Override
    public Observable<Message> call(final Changer2 changer2) {
        return dynamicMessage.last().map(new Func1<Message, Message>() {
            @Override
            public Message call(Message message) {
                if("+".equalsIgnoreCase(message.operation)){
                    message.value = message.value+changer2.value;
                } else if("-".equalsIgnoreCase(message.operation)){
                    message.value = message.value-changer2.value;
                }
                return message;
            }
        });
    }
}));

public static void main(String[] args) throws InterruptedException {

    dynamicMessage.subscribe(new Action1<Message>() {
        @Override
        public void call(Message message) {
            System.out.println(message);
        }
    });


    Thread.sleep(5000000);
}
}

那么我期望的外包是:

消息{值= 1,操作=&#39; +&#39;}
消息{值= 1,操作=&#39; - &#39;}
消息{值= -1,操作=&#39; - &#39;}
消息{值= 1,操作=&#39; +&#39;}
消息{值= 2,操作=&#39; +&#39;}

此外,我想要将所有内容与CombineLatest合并,但后来我发现CombineLatest没有提供哪个元素被更改,如果没有这些信息,我将不知道需要对消息进行哪些更改。 有什么帮助吗?

3 个答案:

答案 0 :(得分:1)

换句话说,您希望 reduce 扫描 您的行动反映一个州的变化。有一个名为 reduce scan的运算符,它完全符合您的要求。它会接受每一个事件,并允许您通过添加先前的转换结果来转换它,这将是您的状态。

interface Changer {
    State apply(State state);
}

class ValueChanger implements Changer {
    ...
    State apply(State state){
        // implement your logic of changing state by this action and return a new one
    }
    ...
}


class OperationChanger implements Changer {
    ...
    State apply(State state){
        // implement your logic of changing state by this action and return a new one
    }
    ...
}

Observable<ValueChanger> valueChangers
Observable<OperationChanger> operationChangers

Observable.merge(valueChangers, operationChangers)
    .scan(initialState, (state, changer) -> changer.apply(state))
    .subscribe(state -> {
        // called every time a change happens
    });

请注意,我更改了您的命名以使其更有意义。另外,我在这里使用Java8 lambda表达式。如果你不能在你的项目中使用它们,只需将它们换成匿名课程。

编辑:使用scan运算符代替reduce,因为它会在整个过程中提供每个结果,而不是仅发出最终结果 < / p>

答案 1 :(得分:1)

做了一些改变,希望能满足你的需求。请查看结果。

static class Message {
    Integer value;
    String operation;

    public Message(Integer value, String operation) {
        this.value = value;
        this.operation = operation;
    }

    @Override
    public String toString() {
        return "Message{" + "value=" + value + ", operation='" + operation
                + '\'' + '}';
    }

    public Message applyChange(Object changer){
        if(changer instanceof Changer1){
            this.operation = ((Changer1)changer).operation;
        }else if(changer instanceof Changer2){
            int v2 = ((Changer2)changer).value;
            if("+".equals(operation)){
                value += v2;
            }else if("-".equals(operation)){
                value -= v2;
            }
        }
        return this;
    }
}

static class Changer1{
    String operation;

    public Changer1(String operation) {
        this.operation = operation;
    }

    @Override
    public String toString() {
        return "Changer1{" + "operation='" + operation + '\'' + '}';
    }
}

static class Changer2{
    Integer value;

    public Changer2(Integer value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Changer2{" + "value=" + value + '}';
    }
}

static Observable<? extends Object> changers1 = Observable
        .just(new Changer1("-"))
        .delay(1, TimeUnit.SECONDS)
        .concatWith(
                Observable.just(new Changer1("+")).delay(2,
                        TimeUnit.SECONDS));

static Observable<? extends Object> changers2 = Observable
        .just(new Changer2(2))
        .delay(2, TimeUnit.SECONDS)
        .concatWith(
                Observable.just(new Changer2(2)).delay(2, TimeUnit.SECONDS));


static Observable<Message> dynamicMessage = Observable
        .just(new Message(1, "+"))
        .flatMap(m -> ((Observable<Object>)changers1).mergeWith((Observable<Object>)changers2).map(c -> m.applyChange(c)));

public static void main(String[] args) throws InterruptedException {
    dynamicMessage.toBlocking().subscribe(v -> System.out.println(v));
}

的变化:

Message有一个新方法,每次发出Changer时都会调用它,它会更改Message对象的值。这是因为你只有一个Message对象,它实际上是init值。

public Message applyChange(Object changer){
    if(changer instanceof Changer1){
        this.operation = ((Changer1)changer).operation;
    }else if(changer instanceof Changer2){
        int v2 = ((Changer2)changer).value;
        if("+".equals(operation)){
            value += v2;
        }else if("-".equals(operation)){
            value -= v2;
        }
    }
    return this;
}

dynamicMessage会根据需要进行修改 -

static Observable<Message> dynamicMessage = Observable
    .just(new Message(1, "+"))
    .flatMap(m -> ((Observable<Object>)changers1)
        .mergeWith((Observable<Object>)changers2)
        .map(c -> m.applyChange(c)));

答案 2 :(得分:0)

好的,我在这里有两个答案。其中一个正在工作,但它有设计问题,即用手控制并发执行的力量。另一个不按设计工作的人(可能在进行一些操作后使reduce运算符不是为所有操作而是为每一对数据工作)。但是我在这里发布自己的答案,因为我找到了更优雅,更正确的解决方案。

但在回答之前,请先看一下这个问题。它为什么挂?答案是:因为运营商last()正在阻止。所以我需要强制它是非阻塞的。根据另一个答案:https://stackoverflow.com/a/37015509/449553,我可以使用BehaviorSubject类。

这是我的工作代码:

    final BehaviorSubject<Message> subject = BehaviorSubject.create(new Message(1, "+"));
    Observable<Message> observable = Observable.<Changer>merge(changers1, changers2).map(new Func1<Changer, Message>() {
        @Override
        public Message call(Changer changer) {
            Message value = subject.getValue();
            Message v = value.applyChange(changer);
            subject.onNext(v);
            return v;
        }
    });

(您将在其他答案herehere中找到缺少的部分代码) 不过,我不会将答案标记为正确,我相信,有人可能想以更恰当的方式自己解决这个难题。

编辑:找到了正确的方法,请参阅标记的答案。