Search code examples
javaandroiduriinputstreamobjectinputstream

Android/Java: How to track progress of InputStream


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?


Solution

  • 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=[]}