继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

能知进度的InputStream和OutputStream

幕布斯6054654
关注TA
已关注
手记 1135
粉丝 218
获赞 1009

文件下载进度、文件上传进度、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


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP