Android Google DriveFile 元数据被缓存而不是从云端获取
Android Google DriveFile metadata is cached and not fetched from the cloud
Burcu Dogan 编写了一些示例代码,展示了如何将本地首选项文件同步到用户的 Google Drive 应用程序文件夹,可在此处找到:https://github.com/googledrive/appdatapreferences-android
我已将此示例转换为使用当前的 Drive SDK,现在随 Google Play 服务一起提供。
如果我使用设备 1 更新云驱动器文件,然后 运行 设备 2 上的以下代码,我将从元数据中获取陈旧的 "modified" 时间戳。我假设这是因为结果来自 Drive 文件的本地缓存:
第 1 步。按名称查找首选项文件,查询:
/**
* Retrieves the preferences file from the appdata folder.
* @return Retrieved preferences file or {@code null}.
* @throws IOException
*/
public DriveFile getPreferencesFile() throws IOException
{
if (mDriveFile != null)
return mDriveFile;
GoogleApiClient googleApiClient = getGoogleApiClient();
if (!googleApiClient.isConnected())
LOGW(TAG, "getPreferencesFile -- Google API not connected");
else
LOGD(TAG, "getPreferencesFile -- Google API CONNECTED");
Query query = new Query.Builder()
.addFilter(Filters.contains(SearchableField.TITLE, FILE_NAME))
.build();
DriveApi.MetadataBufferResult metadataBufferResult =
Drive.DriveApi.query(getGoogleApiClient(), query).await();
if (!metadataBufferResult.getStatus().isSuccess()) {
LOGE(TAG, "Problem while retrieving files");
return null;
}
MetadataBuffer buffer = metadataBufferResult.getMetadataBuffer();
LOGD(TAG, "Preference files found on Drive: " +
buffer.getCount());
if (buffer.getCount() == 0)
{
// return null to indicate the preference file doesn't exist
mDriveFile = null;
// create a new preferences file
// mDriveFile = insertPreferencesFile("{}");
}
else
mDriveFile = Drive.DriveApi.getFile(
getGoogleApiClient(),
buffer.get(0).getDriveId());
// Release the metadata buffer
buffer.release();
return mDriveFile;
}
第 2 步。获取文件的元数据:
// Get the metadata
DriveFile file;
DriveResource.MetadataResult result = file.getMetadata(getGoogleApiClient()).await();
Metadata metadata = result.getMetadata();
// Get the modified dates
metadata.getModifiedDate();
更奇怪的是,在 运行 执行下面的代码(只列出了 appdatafolder 文件及其内容)之后,上面获取的元数据修改日期变得正确了!!为什么???
/**
*
* Simple debug activity that lists all files currently in Drive AppFolder and their contents
*
*/
public class ActivityViewFilesInAppFolder extends BaseActivity {
private static final String TAG = "ActivityViewFilesInAppFolder";
private TextView mLogArea;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add a text view to the window
ScrollView layout = new ScrollView(this);
setContentView(layout);
mLogArea = new TextView(this);
layout.addView(mLogArea);
ApiClientAsyncTask<Void, Void, String> task = new ApiClientAsyncTask<Void, Void, String>(this) {
@Override
protected String doInBackgroundConnected(Void[] params) {
StringBuffer result = new StringBuffer();
MetadataBuffer buffer = Drive.DriveApi.getAppFolder(getGoogleApiClient())
.listChildren(getGoogleApiClient()).await().getMetadataBuffer();
result.append("found " + buffer.getCount() + " files:\n");
for (Metadata m: buffer) {
DriveId id = m.getDriveId();
DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(), id);
DriveContents contents = file.open( getGoogleApiClient(),
DriveFile.MODE_READ_ONLY, null).await().getDriveContents();
FileInputStream is = new FileInputStream(contents.getParcelFileDescriptor()
.getFileDescriptor());
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(is, Charsets.UTF_8));
String line=null; StringBuffer sb=new StringBuffer();
while ((line=bf.readLine()) != null ) {
sb.append(line);
}
contents.discard(getGoogleApiClient());
result.append("*** " + m.getTitle() + "/" + id + "/"
+ m.getFileSize() + "B:\n [" + sb.toString() + "]\n\n");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
buffer.release();
return result.toString();
}
@Override
protected void onPostExecute(String s) {
if (mLogArea != null) {
mLogArea.append(s);
Map<String, ?> values = PreferenceManager
.getDefaultSharedPreferences(ActivityViewFilesInAppFolder.this).getAll();
String localJson = new GsonBuilder().create().toJson(values);
LOGD(TAG, "Local: " + localJson);
LOGD(TAG, "File: " + s);
}
}
};
task.execute();
}
}
元数据是否从缓存的本地副本中读取,除非有什么东西踢它?
有谁知道如何强制这些 API 始终从远程云端硬盘文件中提取结果?
我有你的问题的答案。好吧,“一种回答”,我相信您不会对此感到满意。
我使用了 RESTful API in my app before switching to GDAA. And after I did, I realized that GDAA, another layer with timing delays I have no control over, is causing issues in an app that attempts to keep multiple Android devices synchronized. See SO 22980497 22382099, 22515028, 23073474 并且只是 grep 用于 'requestSync'。
我希望 GDAA 实现某种 GCM 逻辑来同步“幕后”。特别是当有 'addChangeListener()' method that seems to be designed for that. It does not look to be the case (at least not around Sept 2014). So, I backed off to a true-and-tested scheme of using RESTful API to talk to Google Drive with DataProvider and SyncAdapter logic behind it (much like shown in the UDACITY Class here).
我不满意的是,使用 'synchronize' 等术语的 GDAA 文档有些模棱两可,没有告诉我们它是否是 'local' 或 'network' 同步。并且不回答上述 SO 23073474 之类的问题。
看来(我不是 Google 内部人士)GDAA 是为不立即 在设备之间同步的应用程序设计的。不幸的是,这没有被提及 here or here - see 1:59,这让我浪费了很多时间和挫败感。
现在的问题是:我(我们)应该等到我们从 GDAA 获得 'real time' 同步,还是应该继续在 RESTful 之上进行基于本土 GCM 的同步-DataProvider-SyncAdapter?
好吧,我个人将开始研究 GCM 同步,并将维护一个易于使用的迷你应用程序,该应用程序将在 Google Play 服务的新版本问世时测试 GDAA 行为。我会在 'test miniapp' 准备好并在 GitHub 中更新此答案。抱歉,我对问题本身帮助不大。
好吧,我刚刚找到了诱使新驱动器 API 从远程文件而不是本地缓存读取元数据的秘诀。
即使读取元数据不需要打开文件,但事实证明文件需要打开!
所以从云端读取最新元数据的工作代码如下:
DriveFile file;
// Trick Google Drive into fetching the remote file
// which has the latest metadata
file.open( getGoogleApiClient(), DriveFile.MODE_READ_ONLY, null).await();
DriveResource.MetadataResult result = file.getMetadata(getGoogleApiClient()).await();
Metadata metadata = result.getMetadata();
// Get the modified date
metadata.getModifiedDate();
Google 的问题 -- 这是否按预期工作?元数据会被缓存,除非您先打开文件 read_only?
Burcu Dogan 编写了一些示例代码,展示了如何将本地首选项文件同步到用户的 Google Drive 应用程序文件夹,可在此处找到:https://github.com/googledrive/appdatapreferences-android
我已将此示例转换为使用当前的 Drive SDK,现在随 Google Play 服务一起提供。
如果我使用设备 1 更新云驱动器文件,然后 运行 设备 2 上的以下代码,我将从元数据中获取陈旧的 "modified" 时间戳。我假设这是因为结果来自 Drive 文件的本地缓存:
第 1 步。按名称查找首选项文件,查询:
/**
* Retrieves the preferences file from the appdata folder.
* @return Retrieved preferences file or {@code null}.
* @throws IOException
*/
public DriveFile getPreferencesFile() throws IOException
{
if (mDriveFile != null)
return mDriveFile;
GoogleApiClient googleApiClient = getGoogleApiClient();
if (!googleApiClient.isConnected())
LOGW(TAG, "getPreferencesFile -- Google API not connected");
else
LOGD(TAG, "getPreferencesFile -- Google API CONNECTED");
Query query = new Query.Builder()
.addFilter(Filters.contains(SearchableField.TITLE, FILE_NAME))
.build();
DriveApi.MetadataBufferResult metadataBufferResult =
Drive.DriveApi.query(getGoogleApiClient(), query).await();
if (!metadataBufferResult.getStatus().isSuccess()) {
LOGE(TAG, "Problem while retrieving files");
return null;
}
MetadataBuffer buffer = metadataBufferResult.getMetadataBuffer();
LOGD(TAG, "Preference files found on Drive: " +
buffer.getCount());
if (buffer.getCount() == 0)
{
// return null to indicate the preference file doesn't exist
mDriveFile = null;
// create a new preferences file
// mDriveFile = insertPreferencesFile("{}");
}
else
mDriveFile = Drive.DriveApi.getFile(
getGoogleApiClient(),
buffer.get(0).getDriveId());
// Release the metadata buffer
buffer.release();
return mDriveFile;
}
第 2 步。获取文件的元数据:
// Get the metadata
DriveFile file;
DriveResource.MetadataResult result = file.getMetadata(getGoogleApiClient()).await();
Metadata metadata = result.getMetadata();
// Get the modified dates
metadata.getModifiedDate();
更奇怪的是,在 运行 执行下面的代码(只列出了 appdatafolder 文件及其内容)之后,上面获取的元数据修改日期变得正确了!!为什么???
/**
*
* Simple debug activity that lists all files currently in Drive AppFolder and their contents
*
*/
public class ActivityViewFilesInAppFolder extends BaseActivity {
private static final String TAG = "ActivityViewFilesInAppFolder";
private TextView mLogArea;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add a text view to the window
ScrollView layout = new ScrollView(this);
setContentView(layout);
mLogArea = new TextView(this);
layout.addView(mLogArea);
ApiClientAsyncTask<Void, Void, String> task = new ApiClientAsyncTask<Void, Void, String>(this) {
@Override
protected String doInBackgroundConnected(Void[] params) {
StringBuffer result = new StringBuffer();
MetadataBuffer buffer = Drive.DriveApi.getAppFolder(getGoogleApiClient())
.listChildren(getGoogleApiClient()).await().getMetadataBuffer();
result.append("found " + buffer.getCount() + " files:\n");
for (Metadata m: buffer) {
DriveId id = m.getDriveId();
DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(), id);
DriveContents contents = file.open( getGoogleApiClient(),
DriveFile.MODE_READ_ONLY, null).await().getDriveContents();
FileInputStream is = new FileInputStream(contents.getParcelFileDescriptor()
.getFileDescriptor());
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(is, Charsets.UTF_8));
String line=null; StringBuffer sb=new StringBuffer();
while ((line=bf.readLine()) != null ) {
sb.append(line);
}
contents.discard(getGoogleApiClient());
result.append("*** " + m.getTitle() + "/" + id + "/"
+ m.getFileSize() + "B:\n [" + sb.toString() + "]\n\n");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
buffer.release();
return result.toString();
}
@Override
protected void onPostExecute(String s) {
if (mLogArea != null) {
mLogArea.append(s);
Map<String, ?> values = PreferenceManager
.getDefaultSharedPreferences(ActivityViewFilesInAppFolder.this).getAll();
String localJson = new GsonBuilder().create().toJson(values);
LOGD(TAG, "Local: " + localJson);
LOGD(TAG, "File: " + s);
}
}
};
task.execute();
}
}
元数据是否从缓存的本地副本中读取,除非有什么东西踢它?
有谁知道如何强制这些 API 始终从远程云端硬盘文件中提取结果?
我有你的问题的答案。好吧,“一种回答”,我相信您不会对此感到满意。
我使用了 RESTful API in my app before switching to GDAA. And after I did, I realized that GDAA, another layer with timing delays I have no control over, is causing issues in an app that attempts to keep multiple Android devices synchronized. See SO 22980497 22382099, 22515028, 23073474 并且只是 grep 用于 'requestSync'。
我希望 GDAA 实现某种 GCM 逻辑来同步“幕后”。特别是当有 'addChangeListener()' method that seems to be designed for that. It does not look to be the case (at least not around Sept 2014). So, I backed off to a true-and-tested scheme of using RESTful API to talk to Google Drive with DataProvider and SyncAdapter logic behind it (much like shown in the UDACITY Class here).
我不满意的是,使用 'synchronize' 等术语的 GDAA 文档有些模棱两可,没有告诉我们它是否是 'local' 或 'network' 同步。并且不回答上述 SO 23073474 之类的问题。
看来(我不是 Google 内部人士)GDAA 是为不立即 在设备之间同步的应用程序设计的。不幸的是,这没有被提及 here or here - see 1:59,这让我浪费了很多时间和挫败感。
现在的问题是:我(我们)应该等到我们从 GDAA 获得 'real time' 同步,还是应该继续在 RESTful 之上进行基于本土 GCM 的同步-DataProvider-SyncAdapter?
好吧,我个人将开始研究 GCM 同步,并将维护一个易于使用的迷你应用程序,该应用程序将在 Google Play 服务的新版本问世时测试 GDAA 行为。我会在 'test miniapp' 准备好并在 GitHub 中更新此答案。抱歉,我对问题本身帮助不大。
好吧,我刚刚找到了诱使新驱动器 API 从远程文件而不是本地缓存读取元数据的秘诀。
即使读取元数据不需要打开文件,但事实证明文件需要打开!
所以从云端读取最新元数据的工作代码如下:
DriveFile file;
// Trick Google Drive into fetching the remote file
// which has the latest metadata
file.open( getGoogleApiClient(), DriveFile.MODE_READ_ONLY, null).await();
DriveResource.MetadataResult result = file.getMetadata(getGoogleApiClient()).await();
Metadata metadata = result.getMetadata();
// Get the modified date
metadata.getModifiedDate();
Google 的问题 -- 这是否按预期工作?元数据会被缓存,除非您先打开文件 read_only?