7

问题是来自“ DriveId.getResourceId() ”的“resourceID”在新创建的文件(“ DriveFolder.createFile(GAC, meta, cont) ”的产品)上不可用(返回NULL )。如果通过常规列表或查询过程检索文件,则“resourceID”是正确的。

我怀疑这是一个时间/延迟问题,但不清楚是否存在强制刷新的应用程序操作。“ Drive.DriveApi.requestSync(GAC) ”似乎没有效果。

4

2 回答 2

15

更新(2015 年 7 月 22 日)
感谢 Steven Bazyl 的迅速回应(见下面的评论),我终于有了一个使用Completion Events的令人满意的解决方案。这是两个缩小的代码片段,它们在新创建的文件传播到驱动器后立即将ResourceId传递给应用程序:

文件创建,添加变更订阅:

public class CreateEmptyFileActivity extends BaseDemoActivity {
  private static final String TAG = "_X_";

  @Override
  public void onConnected(Bundle connectionHint) {   super.onConnected(connectionHint);

    MetadataChangeSet meta = new MetadataChangeSet.Builder()
      .setTitle("EmptyFile.txt").setMimeType("text/plain")
      .build();

    Drive.DriveApi.getRootFolder(getGoogleApiClient())
      .createFile(getGoogleApiClient(), meta, null,
        new ExecutionOptions.Builder()
          .setNotifyOnCompletion(true)
          .build()
      )
      .setResultCallback(new ResultCallback<DriveFileResult>() {
        @Override
        public void onResult(DriveFileResult result) {
          if (result.getStatus().isSuccess()) {
            DriveId driveId = result.getDriveFile().getDriveId();
            Log.d(TAG, "Created a empty file: " + driveId);
            DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(), driveId);
            file.addChangeSubscription(getGoogleApiClient());
          }
        }
      });
  }
}

事件服务,捕获完成:

public class ChngeSvc extends DriveEventService {
  private static final String TAG = "_X_";

  @Override
  public void onCompletion(CompletionEvent event) {  super.onCompletion(event);
    DriveId driveId = event.getDriveId();
    Log.d(TAG, "onComplete: " + driveId.getResourceId());
    switch (event.getStatus()) {
      case CompletionEvent.STATUS_CONFLICT:  Log.d(TAG, "STATUS_CONFLICT"); event.dismiss(); break;
      case CompletionEvent.STATUS_FAILURE:   Log.d(TAG, "STATUS_FAILURE");  event.dismiss(); break;
      case CompletionEvent.STATUS_SUCCESS:   Log.d(TAG, "STATUS_SUCCESS "); event.dismiss(); break;
    }
  }
}

在正常情况下(wifi),我几乎立即得到ResourceId 。

20:40:53.247﹕Created a empty file: DriveId:CAESABiiAiDGsfO61VMoAA==
20:40:54.305: onComplete, ResourceId: 0BxOS7mTBMR_bMHZRUjJ5NU1ZOWs

……暂时完成。

原始帖子,已弃用,留在这里供参考。

我让这个答案搁置了一年,希望GDAA能够开发出一个可行的解决方案。我唠叨的原因很简单。如果我的应用程序创建了一个文件,它需要使用有意义的 ID(即 ResourceId)将这一事实广播给它的伙伴(例如其他设备)。这是REST Api 下的一项微不足道的任务,一旦成功创建文件,ResourceId 就会返回。

不用说,我理解 GDAA 将应用程序与网络原语、缓存、批处理等隔离开来的哲学……但很明显,在这种情况下,ResourceID 在交付给应用程序之前很久就可用了。

本来,我实现了Cheryl Simon的建议,在一个新创建的文件上添加了一个ChangeListener,希望在文件传播的时候得到ResourceID 。使用来自android-demos 的经典CreateEmptyFileActivity,我将以下测试代码拼凑在一起:

public class CreateEmptyFileActivity extends BaseDemoActivity {
  private static final String TAG = "CreateEmptyFileActivity";

  final private ChangeListener mChgeLstnr = new ChangeListener() {
    @Override
    public void onChange(ChangeEvent event) {
      Log.d(TAG, "event: " + event + " resId: " + event.getDriveId().getResourceId());
    }
  };


  @Override
  public void onConnected(Bundle connectionHint) {   super.onConnected(connectionHint);

    MetadataChangeSet meta = new MetadataChangeSet.Builder()
      .setTitle("EmptyFile.txt").setMimeType("text/plain")
      .build();

    Drive.DriveApi.getRootFolder(getGoogleApiClient())
      .createFile(getGoogleApiClient(), meta, null)
      .setResultCallback(new ResultCallback<DriveFileResult>() {
        @Override
        public void onResult(DriveFileResult result) {
          if (result.getStatus().isSuccess()) {
            DriveId driveId = result.getDriveFile().getDriveId();
            Log.d(TAG, "Created a empty file: " + driveId);
            Drive.DriveApi.getFile(getGoogleApiClient(), driveId).addChangeListener(getGoogleApiClient(), mChgeLstnr);
          }
        }
      });
  }
}

......并且正在等待发生一些事情。文件在几秒钟内被愉快地上传到驱动器,但没有onChange()事件。10 分钟,20 分钟,...我找不到任何方法让 ChangeListener 唤醒。

因此,我能想到的唯一其他解决方案是推动 GDAA。所以我实现了一个简单的处理程序扑克,它会处理元数据直到发生某些事情:

public class CreateEmptyFileActivity extends BaseDemoActivity {
  private static final String TAG = "CreateEmptyFileActivity";

  final private ChangeListener mChgeLstnr = new ChangeListener() {
    @Override
    public void onChange(ChangeEvent event) {
      Log.d(TAG, "event: " + event + " resId: " + event.getDriveId().getResourceId());
    }
  };

  static DriveId driveId;
  private static final int ENOUGH = 4;    // nudge 4x,  1+2+3+4 = 10seconds
  private static int mWait = 1000;
  private int mCnt;
  private Handler mPoker;
  private final Runnable mPoke = new Runnable() { public void run() {
    if (mPoker != null && driveId != null && driveId.getResourceId() == null && (mCnt++ < ENOUGH)) {
      MetadataChangeSet meta = new MetadataChangeSet.Builder().build();
      Drive.DriveApi.getFile(getGoogleApiClient(), driveId).updateMetadata(getGoogleApiClient(), meta).setResultCallback(
        new ResultCallback<DriveResource.MetadataResult>() {
          @Override
          public void onResult(DriveResource.MetadataResult result) {
            if (result.getStatus().isSuccess() && result.getMetadata().getDriveId().getResourceId() != null)
              Log.d(TAG, "resId COOL " + result.getMetadata().getDriveId().getResourceId());
            else
              mPoker.postDelayed(mPoke, mWait *= 2);
          }
        }
      );
    } else {
      mPoker = null;
    }
  }};

  @Override
  public void onConnected(Bundle connectionHint) {   super.onConnected(connectionHint);

    MetadataChangeSet meta = new MetadataChangeSet.Builder()
      .setTitle("EmptyFile.txt").setMimeType("text/plain")
      .build();

    Drive.DriveApi.getRootFolder(getGoogleApiClient())
      .createFile(getGoogleApiClient(), meta, null)
      .setResultCallback(new ResultCallback<DriveFileResult>() {
        @Override
        public void onResult(DriveFileResult result) {
          if (result.getStatus().isSuccess()) {
            driveId = result.getDriveFile().getDriveId();
            Log.d(TAG, "Created a empty file: " + driveId);
            Drive.DriveApi.getFile(getGoogleApiClient(), driveId).addChangeListener(getGoogleApiClient(), mChgeLstnr);

            mCnt = 0;
            mPoker = new Handler();
            mPoker.postDelayed(mPoke, mWait);
          }
        }
      });
  }
}

瞧,4 秒(给或取)后,ChangeListener 提供了一个新的闪亮 ResourceId。当然,ChangeListener 变得过时了,因为扑克程序也获得了 ResourceId。

所以这就是那些等不及 ResourceId 的人的答案。这就引出了后续问题:

当我清楚地看到文件已在很久以前传播并且 GDAA 具有可用的 ResourceId 时,为什么我必须处理元数据(或重新提交内容),很可能会创建不必要的网络流量来获取onChange()事件?

于 2015-07-22T03:19:14.723 回答
9

当新创建的资源提交到服务器时,ResourceIds 变得可用。在设备离线的情况下,这可能在初始文件创建之后任意长时间。不过,它会在创建请求后尽快发生,因此您无需执行任何操作来加快它的速度。

如果你真的需要它,你可以想象使用更改通知来监听 resourceId 的更改。

于 2014-04-05T00:42:37.433 回答