承上篇,在 iOS 中實作 Azure Blob Storage 上傳進度條 解決了在 iOS 上的日常問題,那當然是 Android 也得來上一發,否則豈不是偏心了。
Java 的解法受到 OOP 的啟發,可以很漂亮又有爽度的解決問題,不然學 OOP 是要什麼時候用呢。
首先看一個在 gist 神人的解決方案,他的思路在於使用 Decorator pattern 與 InputStream 搭配,天衣無縫的讓 Java 程式碼直接支援 Azure Blob Storage 的上傳進度取得。
Main.java 是上傳檔案的主要程式,它的重點在於引用了 WatchingInputStream 類別:
package com.cloudriches.sample;
import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;
import java.io.File;
import java.io.FileInputStream;
public class Main implements WatchingInputStream.ProgressListener {
public static void main(String[] args) throws Exception {
Main main = new Main();
main.upload();
}
public void upload() throws Exception {
CloudStorageAccount account = CloudStorageAccount.parse("DefaultEndpointsProtocol=https;AccountName=(your account name);AccountKey=(your account key);EndpointSuffix=core.windows.net");
CloudBlobClient client = account.createCloudBlobClient();
CloudBlobContainer container = client.getContainerReference("files");
CloudBlockBlob blob = container.getBlockBlobReference("A.mp4");
File sourceFile = new File("/Users/dino/A.mp4");
FileInputStream inputStream = new FileInputStream(sourceFile);
WatchingInputStream watchingInputStream = new WatchingInputStream(inputStream, this);
blob.upload(watchingInputStream, sourceFile.length());
}
@Override
public void onAdvance(long at, long length) {
double percentage = (double)at / (double)length;
System.out.println(percentage);
}
}
WatchInputStream.java 的職責除了原 InputStream 的所有職責,外加上取得檔案已讀數量並計算讀取 %,呼叫 onAdvance 事件:
package com.cloudriches.sample;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
// from https://gist.github.com/alterakey/1454764
public class WatchingInputStream extends FilterInputStream {
public interface ProgressListener {
void onAdvance(long at, long length);
}
private int marked = 0;
private long position = 0;
private ProgressListener listener;
public WatchingInputStream(InputStream in, ProgressListener listener) {
super(in);
this.listener = listener;
}
@Override
public int read(byte[] buffer, int offset, int count) throws IOException {
int advanced = super.read(buffer, offset, count);
this.position += advanced;
this.report();
return advanced;
}
@Override
public synchronized void reset() throws IOException {
super.reset();
this.position = this.marked;
}
@Override
public synchronized void mark(int readlimit) {
super.mark(readlimit);
this.marked = readlimit;
}
@Override
public long skip(long byteCount) throws IOException {
long advanced = super.skip(byteCount);
this.position += advanced;
this.report();
return advanced;
}
private void report() {
if (this.listener == null)
return;
try {
this.listener.onAdvance(this.position, this.position + this.in.available());
}
catch (IOException e) {
this.listener.onAdvance(this.position, 0);
}
}
}