如何使用GSON发布大型json文件解析的进度

时间:2022-09-29 21:35:30

Dear *ers,

亲爱的*ers,

I am currently parsing a large json file from my raw resources. I had to change reading line by line to using a Reader object in combination with gson, to escape an out of memory exception. So far, so good.

我目前正在从我的原始资源中解析一个大的json文件。我不得不逐行更改读取使用Reader对象和gson,以逃避内存不足异常。到现在为止还挺好。

Now this all happens in an async task and I want to have the user be notified of the progress in some kind of loading screen by using publishProgress().

现在这一切都发生在异步任务中,我希望通过使用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);

This is the way I'm reading the file for now, but I have no clue if (and how) I can get any kind of progress updates from GSON or the Reader object.

这是我现在正在阅读文件的方式,但我不知道是否(以及如何)我可以从GSON或Reader对象获得任何类型的进度更新。

Any help is greatly appreciated!

任何帮助是极大的赞赏!

1 个解决方案

#1


2  

You have to write a Wrapper around an InputStream (or a Reader).

您必须围绕InputStream(或Reader)编写包装器。

Something like this should work:

像这样的东西应该工作:

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);
    }
}

How to use:

如何使用:

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));

#1


2  

You have to write a Wrapper around an InputStream (or a Reader).

您必须围绕InputStream(或Reader)编写包装器。

Something like this should work:

像这样的东西应该工作:

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);
    }
}

How to use:

如何使用:

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));