【发布时间】:2014-04-04 23:27:04
【问题描述】:
问题是来自 'DriveId.getResourceId()' 的 'resourceID' 在新创建的文件('DriveFolder.createFile(GAC,元,续)')。如果通过常规列表或查询过程检索文件,则“resourceID”是正确的。
我怀疑这是一个时间/延迟问题,但不清楚是否存在强制刷新的应用程序操作。 'Drive.DriveApi.requestSync(GAC)' 似乎没有效果。
【问题讨论】:
问题是来自 'DriveId.getResourceId()' 的 'resourceID' 在新创建的文件('DriveFolder.createFile(GAC,元,续)')。如果通过常规列表或查询过程检索文件,则“resourceID”是正确的。
我怀疑这是一个时间/延迟问题,但不清楚是否存在强制刷新的应用程序操作。 'Drive.DriveApi.requestSync(GAC)' 似乎没有效果。
【问题讨论】:
更新(2015 年 7 月 22 日)
感谢 Steven Bazyl 的及时响应(见下面的 cmets),我终于有了使用 Completion Events 的令人满意的解决方案。这是两个缩小的代码 sn-ps,它们在新创建的文件传播到驱动器后立即将 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);
}
}
});
}
}
... 并且正在等待某事发生。文件在几秒钟内愉快地上传到Drive,但没有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 可用吗?
【讨论】:
当新创建的资源提交到服务器时,ResourceIds 变得可用。在设备离线的情况下,这可能在初始文件创建之后任意长时间。但它会在创建请求后尽快发生,因此您无需执行任何操作来加快速度。
如果你真的需要它,你可以想象使用change notifications 来监听resourceId 的变化。
【讨论】: