【问题标题】:Android/Java: How to track progress of InputStreamAndroid/Java:如何跟踪 InputStream 的进度
【发布时间】:2017-08-06 07:09:34
【问题描述】:

我的 Android 应用程序中有以下代码,不确定这是否是我的谷歌搜索技能,但我找不到关于如何监控 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();
    }
}

上面的代码运行良好,但在内容来自 GMail 的情况下,即使是一个小文件也需要几秒钟来读取和填充 ArrayList。

是否可以显示带有文件/内容读取百分比的进度条?

【问题讨论】:

    标签: java android uri inputstream objectinputstream


    【解决方案1】:

    如果我理解正确,该方法是创建一个装饰器输入流并覆盖一些方法,这些方法会像读取方法或跳过方法一样吟唱输入流状态。然后使用观察者模式通知 moinotr 读取百分比。请参阅以下代码:

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

    Listener 类是一个回调,当有人更改输入流的索引(如读取字节或跳过字节)时将调用该回调。

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

    测试用例代码:

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

    在上面的代码中,我只是打印读取字节的百分比,根据您的要求,您应该更改进程栏的位置。

    这是输出的一部分;

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

      好吧,我想说跟踪进度的最简单方法是使用异步任务或加载器。将您的输入流放入 AsyncTask 并使用其 onProgressUpdate() 方法跟踪进度。

      【讨论】:

        【解决方案3】:

        不适用于通用输入流 - 您不一定知道流的内容有多大。对于特定的应用程序(例如读取磁盘上的文件),您可以获得该信息。对于其他人(例如来自套接字的输入流),您将不知道总长度。对于那些你知道它的大小的人,你当然可以这样做——只需在线程或 AsyncTask 上读取文件。或者,您可以使用不确定的进度条来向用户显示正在进行的工作。

        【讨论】:

        • 我可以查询 Uri 的大小。它们只会通过本地存储而不是通过 HTTP
        猜你喜欢
        • 2016-03-09
        • 1970-01-01
        • 1970-01-01
        • 2017-09-12
        • 1970-01-01
        • 1970-01-01
        • 2021-11-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多