我想部分读取 Google Drive 上的文件(范围请求或部分下载)。此外,我想连续执行 - 仅在读取前一个间隔之后(使用 CountDownLatch)并在单独的线程中读取下一个间隔(Android 禁止主线程中的 HTTP 请求)。为此,我想实现 ByteChannel 方法:
@Override
public int read(final ByteBuffer dst) {
final com.google.api.services.drive.model.File googleFile = mFile.getImpliedFile();
final int bufferLength = dst.capacity();
final int[] bytesReceived = {-1};
final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable(){
public void run() {
byte[] receivedByteArray = getByteArrayGoogle(mService, googleFile, position, bufferLength);
// byte[] receivedByteArray = getByteArrayApache(googleFile, position, bufferLength);
dst.put(receivedByteArray, 0, receivedByteArray.length);
bytesReceived[0] = receivedByteArray.length;
position += receivedByteArray.length;
latch.countDown();
}
}).start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return bytesReceived[0];
}
如果我使用谷歌推荐的库 google-api-services-drive-v2-rev151-1.18.0-rc.jar 和google-api-client-assembly-1.18.0-rc-1.18.0-rc.zip:
private byte[] getByteArrayGoogle(Drive drive, File file, long position, int byteCount) {
String downloadUrl = file.getDownloadUrl();
byte[] receivedByteArray = null;
if (downloadUrl != null && downloadUrl.length() > 0) {
try {
com.google.api.client.http.HttpRequest httpRequestGet = drive.getRequestFactory().buildGetRequest(new GenericUrl(downloadUrl));
httpRequestGet.getHeaders().setRange("bytes=" + position + "-" + (position + byteCount - 1));
com.google.api.client.http.HttpResponse response = httpRequestGet.execute();
InputStream is = response.getContent();
receivedByteArray = IOUtils.toByteArray(is);
response.disconnect();
System.out.println("google-http-client-1.18.0-rc response: [" + position + ", " + (position + receivedByteArray.length - 1) + "]");
} catch (IOException e) {
e.printStackTrace();
}
}
return receivedByteArray;
}
我永远不能阅读超过六个间隔!但是,如果我使用 Apache HTTP 客户端:
private byte[] getByteArrayApache(File file, long position, int byteCount) {
String downloadUrl = file.getDownloadUrl();
byte[] receivedByteArray = null;
if (downloadUrl != null && downloadUrl.length() > 0) {
try {
org.apache.http.client.methods.HttpGet httpRequestGet = new HttpGet(downloadUrl);
httpRequestGet.addHeader("Authorization", "Bearer " + GoogleDriveActivity.getAccessToken(mContext));
httpRequestGet.addHeader("Range", "bytes=" + position + "-" + (position + byteCount - 1));
org.apache.http.HttpResponse response = new DefaultHttpClient().execute(httpRequestGet);
InputStream is = response.getEntity().getContent();
receivedByteArray = IOUtils.toByteArray(is);
System.out.println("apache-http-client response: [" + position + ", " + (position + receivedByteArray.length - 1) + "]");
} catch (IOException e) {
e.printStackTrace();
}
}
return receivedByteArray;
}
我可以阅读所有需要的间隔。
问题似乎出在 com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential 中。请求处理程序
public void intercept(HttpRequest request) throws IOException {
try {
token = getToken();
request.getHeaders().setAuthorization("Bearer " + token);
} catch (GooglePlayServicesAvailabilityException e) {
throw new GooglePlayServicesAvailabilityIOException(e);
} catch (UserRecoverableAuthException e) {
throw new UserRecoverableAuthIOException(e);
} catch (GoogleAuthException e) {
throw new GoogleAuthIOException(e);
}
}
因为我无法获得第七个请求的令牌,并且应用程序总是在调试时冻结。
token = getToken();
1. 出现这种奇怪行为的原因是什么?如何使用 Google API 发出超过六个请求?
2. 还有其他方法可以使用 Google API 进行部分下载吗?
PS 顺便说一句,RequestHandler类有注解@Beta...
评论: 似乎问题出在用于获取令牌的 Google Play 服务专有类 com.google.android.gms.auth.GoogleAccountCredential 中:
GoogleAuthUtil.getToken(context, accountName, scope)
因为我怀疑 GoogleAuthUtil.getToken 必须使用主线程来验证身份验证,但主线程在等待请求结果时被 CountDownLatch 阻塞。因此,我在这一点上陷入僵局。前六个请求是从 AsyncTask 执行的,它们不会阻塞主线程。