severin.julien
severin.julien

Reputation: 1354

Buffering of grouped items with RxJava

I'm trying to implement a stream handling with RxJava. I want to handle different steps.

So far with the code example below, I have a buffer that is shared for all sensors data. I don't understand how to create a buffer for each group and then do my computation. As I'm new to RxJava, I don't understand all the concepts and I'm stuck with my issue.

import io.reactivex.Observable;
import io.reactivex.subjects.PublishSubject;

import java.util.List;
import java.util.concurrent.TimeUnit;

public class Main {

    private static final int SENSOR_TEMPERATURE = 1;
    private static final int SENSOR_HUMIDITY = 2;

    private PublishSubject<Sensor> publishSubject = PublishSubject.create();

    static class Sensor {
        int type;
        float value;

        Sensor(int type, float value) {
            this.type = type;
            this.value = value;
        }
    }

    private PublishSubject<Sensor> listenSensors() {
        return publishSubject;
    }

    private static Sensor getValueAverage(List<Sensor> sensors) {
        int count = sensors.size();
        float total = sensors.stream().map(sensor -> sensor.value).reduce(Float::sum).orElse(0f);
        float avg = total / count;
        return new Sensor(sensors.get(0).type, avg);
    }

    //Map type
    private static String getStringType(int type) {
        if (type == SENSOR_HUMIDITY) {
            return "HUMIDITY";
        }
        else if (type == SENSOR_TEMPERATURE) {
            return "TEMPERATURE";
        }
        return "OTHER";
    }

    private static void emitRandomValue(PublishSubject<Sensor> sensorPublishSubject) throws InterruptedException {

        new Thread(() -> {
            int randomDelay = 0;

            while (true) {
                int randomType = (int) ((Math.random() * 10 % 2) + 1);
                randomDelay = (int) (Math.random() * 3000);
                float randomValue = (float) (Math.random() * 100);
                System.out.println("EMIT: " + getStringType(randomType) + " " + randomValue);
                sensorPublishSubject.onNext(new Sensor(randomType, randomValue));
                try {
                    Thread.sleep(randomDelay);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }).start();
    }
    static Observable<List<Sensor>> flatpMapSensor(List<Sensor> sensors) {
        return Observable
            .fromIterable(sensors)
            .groupBy(s -> s.type)
            .flatMapSingle(Observable::toList);
    }

    // Testing code
    static public void main(String args[]) throws InterruptedException {
        Main main = new Main();
        main.listenSensors()
            .publish(p -> p
                .buffer(20, TimeUnit.SECONDS, 10)
                .filter(list -> !list.isEmpty()))
            .flatMap(Main::flatpMapSensor)
            .map(Main::getValueAverage)
            .subscribe(sensor -> System.out.println("AVG " + getStringType(sensor.type) + " " + sensor.value));
        emitRandomValue(main.publishSubject);

        Thread.sleep(90000);

    }
}

So my question is : How can I have a separate buffer for each sensor type ?

Upvotes: 2

Views: 1261

Answers (1)

ctranxuan
ctranxuan

Reputation: 815

What if you shift the buffer() and groupBy() calls?

static public void main(String args[]) throws InterruptedException {
   Main main = new Main();
   main.listenSensors()
       .groupBy(s -> s.type) // group by type
       .flatMap(l -> l.buffer(20, SECONDS, 10).map(Main::getValueAverage)) // buffer groups by type and compute the average
       .subscribe(sensor -> System.out.println("AVG " + getStringType(sensor.type) + " " + sensor.value));
   emitRandomValue(main.publishSubject);

   Thread.sleep(90000);
}

Upvotes: 1

Related Questions