文件下载进度、文件上传进度、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();
}
}
}
不知道这两个小东西有没有帮助到你们?
网友评论