4

I have a collection of objects, call them obj. They have an act() method. The act() method will eventually cause the event() observable on o to call onComplete.

What is a good way to chain these?

That is, call o.act(), wait for o.event().onComplete and then call the next o2.act(), and so on for indefinite number of o in collection.

So the signature is like so:

public class Item {
    final protected PublishSubject<Object> event = PublishSubject.create();

    public Observable<ReturnType> event() {
        return event;
    }

    public void act() {
        // do a bunch of stuff
        event.onComplete();
    }
}

And then in the consuming code:

Collection<Item> items...
foreach item in items
  item.act -> await item.event().onComplete() -> call next item.act() -> so on
mtyson
  • 8,196
  • 16
  • 66
  • 106
  • Do you need the return of o.act() in o2.act()? If not, could you run all this asynchronously? – Sebas Jan 01 '17 at 14:40
  • @Sebas o2, o3 etc. each might depend on side-effects of the previous execution (but not the actual return value) – mtyson Jan 01 '17 at 14:41
  • So, the order matter, correct? – Sebas Jan 01 '17 at 14:44
  • @Sebas - order matters, yep – mtyson Jan 01 '17 at 14:48
  • Check this then, it may help http://stackoverflow.com/a/26936234/1291428 - it seems `switchmap` will prevent your observables to emit their results before the previous ones are completed – Sebas Jan 01 '17 at 14:56

1 Answers1

2

If I understand correctly, your objects have this kind of signature:

public class Item {
    public Observable<ReturnType> event()...
    public ReturnType act()...
}

So if they were filled out like so:

public class Item {

    private final String data;
    private final Observable<ReturnType> event;

    public Item(String data) {
        this.data = data;

        event = Observable
                .fromCallable(this::act);
    }

    public Observable<ReturnType> event() {
        return event;
    }

    public ReturnType act() {
        System.out.println("Item.act: " + data);
        return new ReturnType();
    }
}

They could then be chained like so:

Item item1 = new Item("a");
Item item2 = new Item("b");
Item item3 = new Item("c");

item1.event()
        .concatWith(item2.event())
        .concatWith(item3.event())
        .subscribe();

Result:

Item.act: a
Item.act: b
Item.act: c

Then if you have an Iterable collection, you could use flatMap:

Iterable<Item> items = Arrays.asList(item1, item2, item3);

Observable.from(items)
        .flatMap(Item::event)
        .subscribe();

Alternative

An alternative that's more like your case might be:

public class Item {
    private final PublishSubject<Void> event = PublishSubject.create();

    private final String data;

    public Item(String data) {
        this.data = data;
    }

    public Observable<Void> event() {
        return event;
    }

    public Void act() {
        System.out.println("Item.act: " + data);
        // do a bunch of stuff
        event.onCompleted();
        return null;
    }
}

usage:

Iterable<Item> iterable = Arrays.asList(item2, item3);

item1.event().
        concatWith(Observable.from(iterable)
                .map(Item::act))
        .subscribe();

item1.act();

But it does not use the event() on items 2 onwards.

weston
  • 54,145
  • 21
  • 145
  • 203
  • That is really close, sorry for the skimpy details. I updated the question using your Item class. thanks – mtyson Jan 01 '17 at 17:32
  • So you want to kick it all off by calling the first `act`? – weston Jan 01 '17 at 17:34
  • That is true, yes! – mtyson Jan 01 '17 at 17:50
  • I think it's a better pattern for work to not be done if there are no observers. That's why work is normally kicked off at subscription. Kicking it off one way for the first item and another way for subsequent items seems smelly. Any reason you need it this way? – weston Jan 01 '17 at 17:54
  • The activity in `item.act()` is system processes that are inherently 'hot'. The preceeding processes may do things like create directories that that following ones depend on. – mtyson Jan 01 '17 at 18:15
  • I think I would need to know more about the whole scenario. – weston Jan 01 '17 at 18:31
  • well I had a go, but not sure if that's what you want – weston Jan 01 '17 at 20:25
  • Impressive... most impressive. (A comment that will make extra sense while you are wearing your vader hat...) – mtyson Jan 01 '17 at 20:34