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