Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
382 views
in Technique[技术] by (71.8m points)

Deleted files status unreliably reported in the new Google Drive Android API (GDAA)

This issue has been bugging me since the inception of the new Google Drive Android Api (GDAA). First discussed here, I hoped it would go away in later releases, but it is still there (as of 2014/03/19). The user-trashed (referring to the 'Remove' action in 'drive.google.com') files/folders keep appearing in both the

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

as well as

  DriveFolder.listChildren(_gac)

methods, even if used with

  Filters.eq(SearchableField.TRASHED, false)

query qualifier, or if I use a filtering construct on the results

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

Using

  Drive.DriveApi.requestSync(_gac);

has no impact. And the time elapsed since the removal varies wildly, my last case was over 12 HOURS. And it is completely random.

What's worse, I can't even rely on EMPTY TRASH in 'drive.google.com', it does not yield any predictable results. Sometime the file status changes to 'isTrashed()' sometimes it disappears from the result list.

As I kept fiddling with this issue, I ended up with the following superawfulhack:

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
}

Not even this helps. The file shows up as healthy even if the file is in the trash (and it's status was double-filtered by query and by metadata test). It can even be happily written into and when inspected in the trash, it is modified.

The conclusion here is that a fix should get higher priority, since it renders multi-platform use of Drive unreliable. It will be discovered by developers right away in the development / debugging process, steering them away.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

While waiting for any acknowledgement from the support team, I devised a HACK that allows a workaround for this problem. Using the same principle as in SO 22295903, the logic involves falling back to RESTful API. Basically, dropping the LIST / QUERY functionality of GDAA.

The high level logic is:

  1. query the RESTful API to retrieve the ID/IDs of file(s) in question
  2. use retrieved ID to get GDAA's DriveId via 'fetchDriveId()'

here are the code snippets to document the process:

1/ initialize both GDAA's 'GoogleApiClient' and RESTful's 'services.drive.Drive'

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/ method that queries the Drive RESTful API, returning GDAA's DriveId to be used by the app.

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;
}

The findObject() method above (again I'm using the 'await()' flavor for simplicity) returns the the Drive objects correctly, reflecting the trashed status with no noticeable delay (implement in non-UI thread).

Again, I would strongly advice AGAINST leaving this in code longer than necassary since it is a HACK with unpredictable effect on the rest of the system.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...