Чтение потока OKIO дважды

Я использую OKHTTP для работы в сети и в настоящее время получаю charStream от response.charStream(), который затем передаю GSON для синтаксического анализа. После синтаксического анализа и раздувания я снова сдуваю модель, чтобы сохранить ее на диск с помощью потока. Кажется, что нужно выполнить дополнительную работу, чтобы перейти от networkReader к Model и DiskWriter. Можно ли с помощью OKIO вместо этого перейти от networkReader к JSONParser (считыватель), а также от networkReader к DiskWriter (считыватель). В основном я хочу иметь возможность читать из сетевого потока дважды.


person FriendlyMikhail    schedule 25.01.2016    source источник


Ответы (1)


Вы можете использовать MirroredSource (взято из этой сути).

public class MirroredSource {

    private final Buffer buffer = new Buffer();
    private final Source source;
    private final AtomicBoolean sourceExhausted = new AtomicBoolean();

    public MirroredSource(final Source source) {
        this.source = source;
    }

    public Source original() {
        return new okio.Source() {

            @Override
            public long read(final Buffer sink, final long byteCount) throws IOException {
                final long bytesRead = source.read(sink, byteCount);
                if (bytesRead > 0) {
                    synchronized (buffer) {
                        sink.copyTo(buffer, sink.size() - bytesRead, bytesRead);
                        // Notfiy the mirror to continue
                        buffer.notify();
                    }
                } else {
                    sourceExhausted.set(true);
                }
                return bytesRead;
            }

            @Override
            public Timeout timeout() {
                return source.timeout();
            }

            @Override
            public void close() throws IOException {
                source.close();
                sourceExhausted.set(true);
                synchronized (buffer) {
                    buffer.notify();
                }
            }
        };
    }

    public Source mirror() {
        return new okio.Source() {

            @Override
            public long read(final Buffer sink, final long byteCount) throws IOException {
                synchronized (buffer) {
                    while (!sourceExhausted.get()) {
                        // only need to synchronise on reads when the source is not exhausted.

                        if (buffer.request(byteCount)) {
                            return buffer.read(sink, byteCount);
                        } else {
                            try {
                                buffer.wait();
                            } catch (final InterruptedException e) {
                                //No op
                            }
                        }
                    }
                }
                return buffer.read(sink, byteCount);
            }

            @Override
            public Timeout timeout() {
                return new Timeout();
            }

            @Override
            public void close() throws IOException { /* not used */ }
        };
    }
}

Использование будет выглядеть так:

MirroredSource mirroredSource = new MirroredSource(response.body().source()); //Or however you're getting your original source
Source originalSource = mirroredSource.original();
Source secondSource = mirroredSource.mirror();
doParsing(originalSource);
writeToDisk(secondSource);
originalSource.close();

Если вам нужно что-то более надежное, вы можете перепрофилировать Relay из OkHttp.

person James McCracken    schedule 28.09.2016
comment
ха! на самом деле это мой пиар, и у меня все еще было несколько проблем. Вот обновленная версия gist.github.com/digitalbuddha/18019a61a0d15eb9f7f53f03685418bb, над которой сейчас работает Джесси Уилсон. аналогичная реализация для OKHTTP Cache2 https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/internal/cache2/Relay.java. - person FriendlyMikhail; 29.09.2016