Android/Java: How to track progress of InputStream

做~自己de王妃 提交于 2021-02-08 05:28:15

问题


I have the following code in my Android app, and not sure whether it is my Googling skills, but am not able to find a good tutorial on how to monitor progress of InputStream.

private void restoreFromUri(Uri uri) {
    try {
        InputStream is = getContentResolver().openInputStream(uri);
        ObjectInputStream ois = new ObjectInputStream(is);
        ArrayList<String> myList = (ArrayList) ois.readObject();
        ois.close();
        is.close();
    } catch (Exception e) {
        Snackbar.make(snackView, e.getMessage(), Snackbar.LENGTH_LONG).show();
    }
}

The above code works well, but in scenarios where the content is coming from GMail, even a small file takes a few seconds to read and populate the ArrayList.

Is it possible to show a progress bar with the percentage of file/content read?


回答1:


If i understand correctly,the approach is create a decorator inputstream and override some method which will chante the inputstream state like read method or skip method.And then use observer pattern notify the moinotr the percent of read.See the following code:

    public static class ProcessInputStream extends InputStream{

    private InputStream in;
    private int length,sumRead;
    private java.util.List<Listener> listeners;
    private double percent;

    public ProcessInputStream(InputStream inputStream,int length) throws IOException{
        this.in=inputStream;
        listeners=new ArrayList<>();
        sumRead=0;
        this.length=length;
    }


    @Override
    public int read(byte[] b) throws IOException {
        int readCount = in.read(b);
        evaluatePercent(readCount);
        return readCount;
    }



    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int readCount = in.read(b, off, len);
        evaluatePercent(readCount);
        return readCount;
    }

    @Override
    public long skip(long n) throws IOException {
        long skip = in.skip(n);
        evaluatePercent(skip);
        return skip;
    }

    @Override
    public int read() throws IOException {
        int read = in.read();
        if(read!=-1){
            evaluatePercent(1);
        }
        return read;
    }

    public ProcessInputStream addListener(Listener listener){
        this.listeners.add(listener);
        return this;
    }

    private void evaluatePercent(long readCount){
        if(readCount!=-1){
            sumRead+=readCount;
            percent=sumRead*1.0/length;
        }
        notifyListener();
    }

    private void notifyListener(){
        for (Listener listener : listeners) {
            listener.process(percent);
        }
    }
}

The Listener class is a callback which will be invoked when someone change the index of inputstream like read bytes or skip bytes.

public interface Listener{
    void process(double percent);
}

The test case code:

    UserInfo userInfo=new UserInfo();
    userInfo.setName("zyr");
    userInfo.setPassword("123");
    userInfo.setTestString(new ArrayList<>());
    System.out.println(userInfo);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos=new ObjectOutputStream(bos);
    oos.writeObject(userInfo);
    byte[] objectBytes = bos.toByteArray();
    oos.close();
    bos.close();


    ProcessInputStream processInputStream = new ProcessInputStream(new ByteArrayInputStream(objectBytes),objectBytes.length);


    processInputStream.addListener(percent -> System.out.println(percent));
    ObjectInputStream ois=new ObjectInputStream(processInputStream);


    UserInfo target = (UserInfo) ois.readObject();
    System.out.println(target);

In the above code,i just print the percent of read bytes,with your requirement,you should change the position of the process bar.

And this is a part of output;

UserInfo{id=0, name='zyr', password='123', testString=[]}
0.008658008658008658
0.017316017316017316
0.021645021645021644
......
......
0.9523809523809523
0.9696969696969697
0.974025974025974
0.9783549783549783
0.9956709956709957
1.0
UserInfo{id=0, name='zyr', password='123', testString=[]}



回答2:


Well, I would say the simplest way to track progress would be to use an Async Task or a Loader. Put your input stream in an AsyncTask and track the progress by using its onProgressUpdate() method.




回答3:


Not for a generic input stream- you don't necessarily know how big the contents of a stream are. For specific applications (reading a file on disk, for example) you can get that information. For others (the input stream from a socket as an example) you won't know the total length. For those you do know the size of, of course you can do that- just read the file on a thread or AsyncTask. Or you could use an indeterminate rogress bar just to show the user that work is happening.



来源:https://stackoverflow.com/questions/45529515/android-java-how-to-track-progress-of-inputstream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!