2017-01-02 51 views
2

使用Google Drive API for Android和堆棧溢出的一些答案,我設法將Google Sign-In應用到我的應用中,並將存儲在用戶設備上的SQLite數據庫備份到Google Drive。使用Google Drive Android API更新SQLite數據庫

僅供參考,這裏是我的數據庫保存到谷歌驅動器(這是在一個名爲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 http://stackoverflow.com/a/33610727/4230345) 
    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雲端硬盤,但是如何更新Google雲端硬盤版本並進行本地更改?

例如,我可以從表A中刪除3行,然後在本地向表B添加5行(到設備的SQLite數據庫),但是如何更新帶有此更改的Google Drive版本?

我曾考慮刪除整個Drive文件並重新上傳,但這會導致該文件的其他DriveId,這是我的理解。

我想知道我是否能夠利用API的修改處理(解釋here),如果設備沒有互聯網連接,更改將排隊上傳。

+0

當你使用數據庫作爲文件時,我不認爲這個問題有任何簡單/優雅的解決方案 – Distjubo

+0

儘管可以計算出一個[工具](https://sqlite.org/sqldiff.html) 2 sqlite數據庫之間的差異 – Distjubo

+0

@Distjubo是的,這就是我懷疑的。你有沒有我可以使用的解決方案(不管它有多麼優雅)。我將如何使用您建議的_sqldiff_工具? –

回答

1

根據this answer,Google Drive的android API已經爲您處理差異計算。所以不需要做任何複雜的事情,就像使用API​​完全重寫那個文件一樣。

您可能還想利用API的透明脫機同步功能。

+0

感謝您的澄清 - 我很高興這裏沒有什麼太難處理;)。在重寫文件時,是否需要執行任何操作以從該文件中刪除內容,還是隻需要寫入該文件,默認情況下它將被覆蓋? –

+0

更新 - 我應該在'WRITE_ONLY'模式下打開文件,如[這裏](https://developers.google.com/drive/android/)和[這裏](https://developers.google.com /驅動器/安卓/文件#opening_the_file_contents_1)? –

+0

是的,多數民衆贊成在它應該如何工作 – Distjubo