2015-01-11 5 views
8

Lieben Stackoverflowers,Wie Fortschritt für große JSON-Datei veröffentlichen Parsen mit Gson

ich zur Zeit eine große JSON-Datei von meinen rohen Ressourcen Parsen. 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 den Benutzer über den Fortschritt in einer Art Ladebildschirm benachrichtigt werden, indem Sie publishProgress() verwenden.

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

Dies ist die Art, wie ich für die Datei jetzt gerade lese, aber ich habe keine Ahnung, ob (und wie) ich jede Art von Fortschritt Updates von Gson oder dem Reader-Objekt bekommen.

Jede Hilfe wird sehr geschätzt!

Antwort

2

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

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 verwenden:

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

Ich weiß nicht, warum dies nur eine Stimme hatte und wurde nicht als korrekt markiert. Das hat mir sehr geholfen, danke dafür. –