Статус удаленных файлов недостоверно сообщается в новом Google Drive Android API (GDAA)

Эта проблема беспокоила меня с момента появления нового Google Drive Android Api (GDAA). Сначала обсуждалось здесь, я надеялся, что это исчезнет в более поздних версиях, но это все еще там (по состоянию на 2014/03/19). Файлы/папки, удаленные пользователем (ссылаясь на действие «Удалить» на «drive.google.com»), продолжают появляться как в

  Drive.DriveApi.query(_gac, query), and  
  DriveFolder.queryChildren(_gac, query)

так же как

  DriveFolder.listChildren(_gac)

методы, даже если они используются с

  Filters.eq(SearchableField.TRASHED, false)

квалификатор запроса, или если я использую фильтрующую конструкцию для результатов

for (Metadata md : result.getMetadataBuffer()) {
  if ((md == null) || (!md.isDataValid()) || md.isTrashed()) continue;
  dMDs.add(new DrvMD(md));
}

С использованием

  Drive.DriveApi.requestSync(_gac);

не имеет никакого влияния. И время, прошедшее с момента удаления, сильно различается, мой последний случай был более 12 ЧАСОВ. И это совершенно случайно.

Что еще хуже, я даже не могу полагаться на ПУСТОЙ КОРЗИНУ в 'drive.google.com', это не дает никаких предсказуемых результатов. Иногда статус файла меняется на «isTrashed()», иногда он исчезает из списка результатов.

Пока я продолжал возиться с этой проблемой, я получил следующий супер-ужасный хак:

find file with TRASH status equal FALSE 
if (file found and is not trashed) {
  try to write content
  if ( write content fails)
    create a new file
}

Даже это не помогает. Файл отображается как исправный, даже если файл находится в корзине (и его статус был дважды отфильтрован по запросу и по тесту метаданных). В него можно даже радостно записать и при осмотре в хлам модифицировать.

Вывод здесь состоит в том, что исправление должно иметь более высокий приоритет, поскольку оно делает многоплатформенное использование Диска ненадежным. Это будет обнаружено разработчиками сразу в процессе разработки/отладки, отпугивая их.


person seanpj    schedule 19.03.2014    source источник
comment
В SO есть подтверждение этой проблемы: stackoverflow.com/questions/21713482/ (ответ Якоба).   -  person seanpj    schedule 20.03.2014
comment
requestSync().await() устранил проблему для меня.   -  person Yaroslav Mytkalyk    schedule 15.04.2014


Ответы (1)


Ожидая подтверждения от службы поддержки, я разработал HACK, позволяющий обойти эту проблему. проблема. Используя тот же принцип, что и в SO 22295903, логика предполагает возврат к RESTful API. По сути, отказ от функций LIST/QUERY GDAA.

Логика высокого уровня:

  1. запросите RESTful API, чтобы получить идентификатор/идентификаторы рассматриваемого файла (файлов).
  2. использовать полученный идентификатор для получения GDAA DriveId через 'fetchDriveId()'

вот фрагменты кода для документирования процесса:

1/ инициализировать 'GoogleApiClient' GDAA и services.drive.Drive' RESTful.

GoogleApiClient _gac;
com.google.api.services.drive.Drive _drvSvc;

void init(Context ctx, String email){
  // build GDAA  GoogleApiClient
  _gac = new GoogleApiClient.Builder(ctx).addApi(com.google.android.gms.drive.Drive.API)
    .addScope(com.google.android.gms.drive.Drive.SCOPE_FILE).setAccountName(email)
    .addConnectionCallbacks(ctx).addOnConnectionFailedListener(ctx).build();
  // build RESTFul (DriveSDKv2) service to fall back to  
  GoogleAccountCredential crd = GoogleAccountCredential
  .usingOAuth2(ctx, Arrays.asList(com.google.api.services.drive.DriveScopes.DRIVE_FILE));
  crd.setSelectedAccountName(email);
  _drvSvc = new com.google.api.services.drive.Drive.Builder(
                       AndroidHttp.newCompatibleTransport(), new GsonFactory(), crd).build();
}

2/ метод, который запрашивает Drive RESTful API, возвращая DriveId GDAA для использования приложением.

String qry = "title = 'MYFILE' and mimeType = 'text/plain' and trashed = false";
DriveId findObject(String qry) throws Exception {
  DriveId dId = null;
  try {
    final FileList gLst = _drvSvc.files().list().setQ(query).setFields("items(id)").execute();
    if (gLst.getItems().size() == 1) {
      String sId = gLst.getItems().get(0).getId();
      dId = Drive.DriveApi.fetchDriveId(_gac, sId).await().getDriveId();
    } else if (gLst.getItems().size() > 1)
      throw new Exception("more then one folder/file found");
  } catch (Exception e) {}
  return dId;
}

Вышеприведенный метод findObject() (опять же для простоты я использую вариант 'await()') правильно возвращает объекты Drive, отражая статус уничтожения без заметной задержки (реализуется в потоке, отличном от пользовательского интерфейса).

Опять же, я настоятельно рекомендую НЕ оставлять это в коде длиннее, чем необходимо, поскольку это ВЗЛОМ с непредсказуемым эффектом на остальную часть системы.

person seanpj    schedule 22.03.2014