Android/Java: 如何跟踪 InputStream 的进度

Android/Java: How to track progress of InputStream

我的 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。

是否可以显示进度条 file/content 阅读的百分比?

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

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

如果我理解正确,该方法是创建一个装饰器输入流并覆盖一些方法,该方法将像读取方法一样吟唱输入流状态或跳过 method.And 然后使用观察者模式通知 moinotr [=25 的百分比=] 以下代码:

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

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

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