使用Google Drive Android API更新SQLite数据库

4

使用Google Drive API for Android和一些在Stack Overflow上找到的答案,我成功地将Google登录集成到我的应用程序中,并将用户设备上存储的SQLite数据库备份到Google Drive。

供参考,以下是我如何将数据库保存到Google Drive(这是在名为DriveDbHandlerfinal class中完成的):

private static final String LOG_TAG = "DriveDbHandler";

private static final String PACKAGE_NAME = "com.package.example";

private static final String DATABASE_PATH =
        "/data/data/" + PACKAGE_NAME + "/databases/" + DbHelper.DATABASE_NAME;

private static final String FILE_NAME = DbHelper.DATABASE_NAME;
private static final String MIME_TYPE = "application/x-sqlite-3";

private DriveDbHandler() {
}


public static void tryCreatingDbOnDrive(final GoogleApiClient googleApiClient) {
    // We need to check if the database already exists on Google Drive. If so, we won't create
    // it again.

    Query query = new Query.Builder()
            .addFilter(Filters.and(
                    Filters.eq(SearchableField.TITLE, FILE_NAME),
                    Filters.eq(SearchableField.MIME_TYPE, MIME_TYPE)))
            .build();
    DriveFolder appFolder = Drive.DriveApi.getAppFolder(googleApiClient);

    appFolder.queryChildren(googleApiClient, query).setResultCallback(
            new ResultCallback<DriveApi.MetadataBufferResult>() {
                @Override
                public void onResult(@NonNull DriveApi.MetadataBufferResult metadataBufferResult) {
                    if (!metadataBufferResult.getStatus().isSuccess()) {
                        Log.e(LOG_TAG, "Query for " + FILE_NAME + " unsuccessful!");
                        return;
                    }

                    int count = metadataBufferResult.getMetadataBuffer().getCount();

                    Log.d(LOG_TAG, "Successfully ran query for " + FILE_NAME + " and found " +
                            count + " results");

                    if (count > 1) {
                        Log.e(LOG_TAG, "App folder contains more than one database file! " +
                                "Found " + count + " matching results.");
                        return;
                    }

                    // Create the database on Google Drive if it doesn't exist already
                    if (count == 0) {
                        Log.d(LOG_TAG, "No existing database found on Google Drive");
                        saveToDrive(googleApiClient);
                    }
                }
            });
}

private static void saveToDrive(final GoogleApiClient googleApiClient) {
    Log.d(LOG_TAG, "Starting to save to drive...");

    // Create content from file
    Drive.DriveApi.newDriveContents(googleApiClient).setResultCallback(
            new ResultCallback<DriveApi.DriveContentsResult>() {
                @Override
                public void onResult(@NonNull DriveApi.DriveContentsResult driveContentsResult) {
                    if (!driveContentsResult.getStatus().isSuccess()) {
                        Log.w(LOG_TAG, "Drive contents result not a success! " +
                                "Not saving data to drive.");
                        return;
                    }

                    Log.d(LOG_TAG, "Created drive contents for file");
                    createNewFile(googleApiClient, driveContentsResult.getDriveContents());
                }
            });
}

private static void createNewFile(GoogleApiClient googleApiClient, DriveContents driveContents) {
    // Write file to contents (see https://dev59.com/VpDea4cB1Zd3GeqPh-WN#33610727)
    File file = new File(DATABASE_PATH);
    OutputStream outputStream = driveContents.getOutputStream();
    try {
        InputStream inputStream = new FileInputStream(file);
        byte[] buf = new byte[4096];
        int c;
        while ((c = inputStream.read(buf, 0, buf.length)) > 0) {
            outputStream.write(buf, 0, c);
            outputStream.flush();
        }
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    Log.d(LOG_TAG, "Written file to output stream of drive contents");

    // Create metadata
    MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
            .setTitle(FILE_NAME)
            .setMimeType(MIME_TYPE)
            .build();

    // Create the file on Google Drive
    DriveFolder folder = Drive.DriveApi.getAppFolder(googleApiClient);
    folder.createFile(googleApiClient, metadataChangeSet, driveContents).setResultCallback(
            new ResultCallback<DriveFolder.DriveFileResult>() {
        @Override
        public void onResult(@NonNull DriveFolder.DriveFileResult driveFileResult) {
            if (!driveFileResult.getStatus().isSuccess()) {
                Log.w(LOG_TAG, "File did not get created in Google Drive!");
                return;
            }

            Log.i(LOG_TAG, "Successfully created file in Google Drive");
        }
    });
}

这是我的问题:
我可以将数据库保存到Google Drive中,但如何使用本地所做的更改更新Google Drive版本?
例如,我可以从表A中删除3行,然后在本地向表B中添加5行(到设备的SQLite数据库),但如何使用此更改更新Google Drive版本?
我考虑过删除整个Drive文件并重新上传它,但据我了解,这将导致该文件的不同DriveId。
我想知道是否能够利用API的修改处理功能(在这里解释),其中如果设备没有互联网连接,则对更改进行排队上传。

我认为当你将数据库用作文件时,这个问题没有任何简单/优雅的解决方案。 - Distjubo
有一个工具,可以计算2个SQLite数据库之间的差异。 - Distjubo
@Distjubo 是的,这正是我怀疑的。您有任何解决方法(无论多么优秀),可以提供给我使用吗?您建议的_sqldiff_工具该如何使用? - Farbod Salamat-Zadeh
sqldiff只有在你将在线文件作为数据库插入/更新时才能使用。但由于你没有这样做,你必须复制上次发送到gdrive的文件,计算差异并进行修补。 - Distjubo
@Distjubo 为了澄清,我正在使用Android API,而不是REST API。我该如何修改数据库的Google Drive版本(使用Android API)? - Farbod Salamat-Zadeh
1个回答

3
根据这个答案,Google Drive的Android API已经为您处理了差异计算。因此,没有必要做任何复杂的事情,只需像完全重写该文件一样使用API即可。
您还可以利用API的透明离线同步功能。

谢谢你的澄清 - 很高兴这里没有太复杂的事情要做 ;) 。当重新编写文件时,我需要做些什么来删除文件中的内容吗?还是只需直接写入,它会默认覆盖原有内容? - Farbod Salamat-Zadeh
更新 - 我是否应该按照此处和此处所述在“WRITE_ONLY”模式下打开文件以更新文件内容? - Farbod Salamat-Zadeh
谢谢你的帮助 - 我会尝试一下并告诉你我使用它的情况。 - Farbod Salamat-Zadeh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接