Frage So veröffentlichen Sie den Fortschritt für die Analyse großer json-Dateien mit GSON


Sehr geehrte Stackoverflowers,

Ich analysiere gerade eine große JSON-Datei von meinen rohen Ressourcen. Ich musste Zeile für Zeile lesen, um ein Reader-Objekt in Kombination mit gson zu verwenden, um eine Ausnahme wegen zu wenig Speicher zu vermeiden. So weit, ist es gut.

Jetzt passiert das alles in einer asynchronen Aufgabe und ich möchte, dass der Benutzer über den Fortschritt in irgendeiner Art von Ladebildschirm benachrichtigt wird, indem er verwendet publishProgress().

InputStream raw = getResources().openRawResource(R.raw.json);
Reader rd = new BufferedReader(new InputStreamReader(raw));
Gson gson = new Gson();
mReadObjects = gson.fromJson(rd, ReadObjectList.class);

So lese ich die Datei jetzt, aber ich habe keine Ahnung, ob (und wie) ich irgendwelche Fortschrittsaktualisierungen von GSON oder dem Reader-Objekt bekommen kann.

Jede Hilfe wird sehr geschätzt!


8
2018-01-11 18:01


Ursprung


Antworten:


Sie müssen einen Wrapper um einen schreiben InputStream (oder ein Reader).

So etwas sollte funktionieren:

public class ProgressInputStream extends FilterInputStream {
    private final int size;
    private long bytesRead;
    private int percent;
    private List<Listener> listeners = new ArrayList<>();

    public ProgressInputStream(InputStream in) {
        super(in);
        try {
            size = available();
            if (size == 0) throw new IOException();
        } catch (IOException e) {
            throw new RuntimeException("This reader can only be used on InputStreams with a known size", e);
        }
        bytesRead = 0;
        percent = 0;
    }

    public void addListener(Listener listener) {
        listeners.add(listener);
    }

    public void removeListener(Listener listener) {
        listeners.remove(listener);
    }

    @Override
    public int read() throws IOException {
        int b = super.read();
        updateProgress(1);
        return b;
    }

    @Override
    public int read(@NonNull byte[] b) throws IOException {
        return updateProgress(super.read(b));
    }

    @Override
    public int read(@NonNull byte[] b, int off, int len) throws IOException {
        return updateProgress(super.read(b, off, len));
    }

    @Override
    public long skip(long n) throws IOException {
        return updateProgress(super.skip(n));
    }

    @Override
    public void mark(int readLimit) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void reset() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean markSupported() {
        return false;
    }

    private <T extends Number> T updateProgress(T numBytesRead) {
        if (numBytesRead.longValue() > 0) {
            bytesRead += numBytesRead.longValue();
            if (bytesRead * 100 / size > percent) {
                percent = (int) (bytesRead * 100 / size);
                for (Listener listener : listeners) {
                    listener.onProgressChanged(percent);
                }
            }
        }
        return numBytesRead;
    }

    public interface Listener {
        void onProgressChanged(int percentage);
    }
}

Wie benutzt man:

ProgressInputStream raw = new ProgressInputStream(getResources().openRawResource(R.raw.json));
raw.addListener(new ProgressInputStream.Listener() {
    @Override
    public void onProgressChanged(int percentage) {
        publishProgress(percentage);
    }
});
Reader rd = new BufferedReader(new InputStreamReader(raw));

2
2017-07-22 18:47