使用Retrofit2.0实现Google Drive文件上传进度显示

上一篇文章中,我们完成了Retrofit2.0接口的定义及基本的调用。
不知大家是否关注到DriveApi.uploadFileMutil()这个接口方法需要传入两个MultipartBody.Part对象,分别对应Metadata part和Media part,如何实现这里的Part对象呢?分为两部分:

Metadata Part

这部分比较简单,MultipartBody.Part.create()方法直接创建即可:

1
2
3
4
String content = "{\"name\": \"" + fileName + "\"}";
MediaType contentType = MediaType.parse("application/json; charset=UTF-8");
MultipartBody.Part metaPart =
MultipartBody.Part.create(RequestBody.create(contentType, content));

Media Part

需要我们自己实现一个RequestBody对象,并重写里面的contentType()writeTo()方法。代码可以参考StackOverflow上的这个回答:Is it possible to show progress bar when upload image via Retrofit 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class ProgressRequestBody extends RequestBody {
private File mFile;
private String mPath;
private UploadCallbacks mListener;

private static final int DEFAULT_BUFFER_SIZE = 2048;

public interface UploadCallbacks {
void onProgressUpdate(int percentage);
void onError();
void onFinish();
}

public ProgressRequestBody(final File file, final UploadCallbacks listener) {
mFile = file;
mListener = listener;
}

@Override
public MediaType contentType() {
// i want to upload only images
return MediaType.parse("image/*");
}

@Override
public void writeTo(BufferedSink sink) throws IOException {
long fileLength = mFile.length();
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
FileInputStream in = new FileInputStream(mFile);
long uploaded = 0;

try {
int read;
Handler handler = new Handler(Looper.getMainLooper());
while ((read = in.read(buffer)) != -1) {

uploaded += read;
sink.write(buffer, 0, read);
// update progress on UI thread
handler.post(new ProgressUpdater(uploaded, fileLength));
}
} finally {
in.close();
}
}

private class ProgressUpdater implements Runnable {
private long mUploaded;
private long mTotal;
public ProgressUpdater(long uploaded, long total) {
mUploaded = uploaded;
mTotal = total;
}

@Override
public void run() {
mListener.onProgressUpdate((int)(100 * mUploaded / mTotal));
}
}
}

注意SO这个回答贴出的代码还有点问题,下面这句应该放在while循环的最下面,否则你最后一直只能收到99%。

1
2
// update progress on UI thread
handler.post(new ProgressUpdater(uploaded, fileLength));

Callback

然后实现UploadCallbacks接口里的相关回调即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MyActivity extends AppCompatActivity implements ProgressRequestBody.UploadCallbacks {
ProgressBar progressBar;
ProgressRequestBody mBody;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
progressBar = findViewById(R.id.progressBar);
mBody = new ProgressRequestBody(mFile, this);
}

@Override
public void onProgressUpdate(int percentage) {
// set current progress
progressBar.setProgress(percentage);
}

@Override
public void onError() {
// do something on error
}

@Override
public void onFinish() {
// do something on upload finished
// for example start next uploading at queue
progressBar.setProgress(100);
}

}

最后同样调用MultipartBody.Part.create()创建即可:

1
MultipartBody.Part dataPart = MultipartBody.Part.create(mBody);