1

我想部分读取 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 执行的,它们不会阻塞主线程。

4

0 回答 0