Google ドライブのファイルを部分的に読みたい (範囲リクエストまたは部分ダウンロード)。さらに、私はそれを連続して行いたい-前の間隔が読み取られた直後に(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 が推奨するライブラリ 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;
}
私は決して 6 区間以上読むことができません! ただし、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 にあるようです。RequestHandler
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);
}
}
7番目のリクエストのトークンを取得できず、デバッグ中のこの時点でアプリケーションが常にフリーズするためです。
token = getToken();
1. その奇妙な動作の理由と、Google API で 6 つ以上のリクエストを行う方法は?
2. Google API を使用して部分ダウンロードを行う他の方法はありますか?
PS ちなみに、クラスRequestHandlerにはアノテーション @Beta があります...
コメント:トークンを取得するために使用される Google Play Service 独自のクラス com.google.android.gms.auth.GoogleAccountCredential に問題があるようです:
GoogleAuthUtil.getToken(context, accountName, scope)
GoogleAuthUtil.getToken はメインスレッドを使用して認証を検証する必要があると思われますが、メインスレッドはリクエスト結果の待機中に CountDownLatch によってブロックされます。したがって、私はこの時点でデッドロックを抱えています。最初の 6 つの要求は AsyncTask から実行され、メイン スレッドをブロックしません。