为了账号安全,请及时绑定邮箱和手机立即绑定

能知进度的InputStream和OutputStream

标签:
Java

文件下载进度、文件上传进度、zip解压进度似乎在常见的app中很常见,进度值是怎么算出来的呢,原理再简单不过,进度=当前已传输大小/总大小。

如果算进度的代码写在业务中感觉不是太美观,也违背了解耦思路,毕竟进度计算是个很单一的功能,今天把以前写过的ProgressAwareInputStream(对应下载)和ProgressAwareOutputStream(对应上传)2个小东西拿出来溜溜:把进度计算融入Stream内部仅以listener告知进度情况。

/**
 * Interface for classes that want to monitor this stream
 */public interface OnProgressListener {    /**
     * This callback should only be used to alert user download failed.
     */
    void onError(String errorMsg);    /**
     * This callback should only be used to update download progress UI
     * @param percentage download progress
     */
    void onProgress(int percentage);    /**
     * This callback should be used to do like open downloaded file.
     */
    void onCompleted();
}

这是进度回调,很明确告知了传输进度、错误(及原因)、传输结束。

public class ProgressAwareInputStream extends InputStream {    private InputStream inputStream;    private long fileSize;    private long localSize;    
    private long lastPercent;    private OnProgressListener listener;    public ProgressAwareInputStream(InputStream in, long fileSize, long localSize) {        this.inputStream = in;        this.fileSize = fileSize;        this.localSize = localSize;        // init progress
        this.lastPercent = (int) (this.localSize * 100 / this.fileSize);
    }    public void setOnProgressListener(OnProgressListener listener) {        this.listener = listener;
    }    @Override
    public int read() {        try{            int readCount = inputStream.read();
            localSize += readCount;
            checkProgress();            return readCount;
        } catch (IOException e) {
            e.printStackTrace();
            listener.onError(e.getMessage());            return -1;
        }
    }    @Override
    public int read(@NonNull byte[] b) {        try{            int readCount = inputStream.read(b);
            localSize += readCount;
            checkProgress();            return readCount;
        } catch (IOException e) {
            e.printStackTrace();
            listener.onError(e.getMessage());            return -1;
        }
    }    @Override
    public int read(@NonNull byte[] b, int offset, int length) {        try{            int readCount = inputStream.read(b, offset, length);
            localSize += readCount;
            checkProgress();            return readCount;
        } catch (IOException e) {
            e.printStackTrace();
            listener.onError(e.getMessage());            return -1;
        }
    }    private void checkProgress() {        int percent = (int) (localSize * 100 / fileSize);        
        // check whether progress is updated
        if (percent - lastPercent >= 1) {
            lastPercent = percent;            if (listener != null){
                listener.onProgress(percent);
            }
        }        
        // check whether download is completed
        if(percent == 100 && listener != null){
            listener.onCompleted();
        }
    }    @Override
    public void close() {        try{
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            listener.onError(e.getMessage());
        }
    }    @Override
    public int available(){        try{            return inputStream.available();
        } catch (IOException e) {
            e.printStackTrace();
            listener.onError(e.getMessage());            return -1;
        }
    }    @Override
    public void mark(int readlimit) {
        inputStream.mark(readlimit);
    }    @Override
    public synchronized void reset() {        try{
            inputStream.reset();
        } catch (IOException e) {
            e.printStackTrace();
            listener.onError(e.getMessage());
        }
    }    @Override
    public boolean markSupported() {        return inputStream.markSupported();
    }    @Override
    public long skip(long n){        try{            return inputStream.skip(n);
        } catch (IOException e) {
            e.printStackTrace();
            listener.onError(e.getMessage());            return -1;
        }
    }
}

思路很简单,就是override InputStream的内部所有影响进度的read()方法并把计算融入其中,有没有一种穿着狼皮的羊的感觉?

其实,ProgressAwareOutputStream也类似原理,就直接贴代码了:

public class ProgressAwareOutputStream extends OutputStream {    private OutputStream outputStream;    private long fileSize;    private long uploadedSize;    private long lastPercent;    private OnProgressListener listener;    
    public ProgressAwareOutputStream(OutputStream out, long fileSize, long uploadedSize){        this.outputStream = out;        this.fileSize = fileSize;        this.uploadedSize = uploadedSize;
    }    
    public void setOnProgressListener(OnProgressListener listener) {        this.listener = listener;
    }    @Override
    public void write(int oneByte) throws IOException {        try{
            outputStream.write(oneByte);
            uploadedSize += 1;
            checkProgress();
        } catch (IOException e) {
            e.printStackTrace();
            listener.onError(e.getMessage());
        }
    }    
    @Override
    public void write(@NonNull byte[] buffer, int offset, int count) throws IOException {        try{
            outputStream.write(buffer, offset, count);
            uploadedSize += count;
            checkProgress();
        } catch (IOException e){
            listener.onError(e.getMessage());
        }
    }    
    @Override
    public void write(@NonNull byte[] buffer) throws IOException {        try{
            outputStream.write(buffer);
            uploadedSize += buffer.length;
            checkProgress();
        }catch(IOException e){
            listener.onError(e.getMessage());
        }
    }    
    @Override
    public void close() throws IOException {        try{
            outputStream.close();
        }catch(IOException e){
            listener.onError(e.getMessage());
        }
    }    
    public OutputStream getInnerOutputStream(){        return outputStream;
    }    
    private void checkProgress() {        int percent = (int) (uploadedSize * 100 / fileSize);        
        // check whether progress is updated
        if (percent - lastPercent >= 1) {
            lastPercent = percent;            if (listener != null){
                listener.onProgress(percent);
            }
        }        
        // check whether download is completed
        if(percent == 100 && listener != null){
            listener.onCompleted();
        }
    }



作者:生活简单些
链接:https://www.jianshu.com/p/91adb6deafe4


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消