web-dev-qa-db-ja.com

Googleドライブを使用したSQLiteデータベースのバックアップと復元

SDカードにデータベースのバックアップを作成してそこから復元することができましたが、バックアップの目的はデータの安全性を確保することであり、この場合、物理デバイス自体が破損、紛失、または自発的に燃焼するため、SDカード上のバックアップも同様に燃焼します。したがって、この場合、バックアップを元の場所と同じ場所に置くと、バックアップを作成する目的が完全に損なわれます。

そこで、私はGoogleドライブをより安全な場所としてdbファイルを保持することを考えました。それは無料です。私はGoogleの quickstart デモをのぞいてみましたが、うまくいきました。しかし、私はまだこれを私の場合にどのように行うのか分かりません。

私がいじくるコードをいくつか見つけましたが、それはまだいくつかの非推奨メソッドを使用しており、これまでのところ、非推奨領域を省略したときにのみ実行できましたが、Googleドライブに空のバイナリファイルしか作成されないので、非推奨領域と思います実際にDBバックアップコンテンツをアップロードする場所です。誰かが助けてくれるなら、それは大歓迎です。

誰かがそれを使用して私に説明することができるように、私はそれを以下に残しておきます。また、以下の非推奨のメソッドにもマークを付けました。これは、もうすぐ終わりです。

public class ExpectoPatronum extends Activity implements ConnectionCallbacks, OnConnectionFailedListener {

private static final String TAG = "MainActivity";
private GoogleApiClient api;
private boolean mResolvingError = false;
private DriveFile mfile;
private static final int DIALOG_ERROR_CODE =100;
private static final String DATABASE_NAME = "demodb";
private static final String GOOGLE_DRIVE_FILE_NAME = "sqlite_db_backup";

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Create the Drive API instance
    api = new GoogleApiClient.Builder(this).addApi(Drive.API).addScope(Drive.SCOPE_FILE).
            addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
}

@Override
public void onStart() {
    super.onStart();
    if(!mResolvingError) {
        api.connect(); // Connect the client to Google Drive
    }
}

@Override
public void onStop() {
    super.onStop();
    api.disconnect(); // Disconnect the client from Google Drive
}

@Override
public void onConnectionFailed(ConnectionResult result) {
    Log.v(TAG, "Connection failed");
    if(mResolvingError) { // If already in resolution state, just return.
        return;
    } else if(result.hasResolution()) { // Error can be resolved by starting an intent with user interaction
        mResolvingError = true;
        try {
            result.startResolutionForResult(this, DIALOG_ERROR_CODE);
        } catch (SendIntentException e) {
            e.printStackTrace();
        }
    } else { // Error cannot be resolved. Display Error Dialog stating the reason if possible.
        ErrorDialogFragment fragment = new ErrorDialogFragment();
        Bundle args = new Bundle();
        args.putInt("error", result.getErrorCode());
        fragment.setArguments(args);
        fragment.show(getFragmentManager(), "errordialog");
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if(requestCode == DIALOG_ERROR_CODE) {
        mResolvingError = false;
        if(resultCode == RESULT_OK) { // Error was resolved, now connect to the client if not done so.
            if(!api.isConnecting() && !api.isConnected()) {
                api.connect();
            }
        }
    }
}

@Override
public void onConnected(Bundle connectionHint) {
    Log.v(TAG, "Connected successfully");

    /* Connection to Google Drive established. Now request for Contents instance, which can be used to provide file contents.
       The callback is registered for the same. */
    Drive.DriveApi.newDriveContents(api).setResultCallback(contentsCallback);
}

final private ResultCallback<DriveApi.DriveContentsResult> contentsCallback = new ResultCallback<DriveApi.DriveContentsResult>() {

    @Override
    public void onResult(DriveApi.DriveContentsResult result) {
        if (!result.getStatus().isSuccess()) {
            Log.v(TAG, "Error while trying to create new file contents");
            return;
        }

        String mimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType("db");
        MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                .setTitle(GOOGLE_DRIVE_FILE_NAME) // Google Drive File name
                .setMimeType(mimeType)
                .setStarred(true).build();
        // create a file on root folder
        Drive.DriveApi.getRootFolder(api)
                .createFile(api, changeSet, result.getDriveContents())
                .setResultCallback(fileCallback);
    }

};

final private ResultCallback<DriveFileResult> fileCallback = new ResultCallback<DriveFileResult>() {

    @Override
    public void onResult(DriveFileResult result) {
        if (!result.getStatus().isSuccess()) {
            Log.v(TAG, "Error while trying to create the file");
            return;
        }
        mfile = result.getDriveFile();
        mfile.open(api, DriveFile.MODE_WRITE_ONLY, null).setResultCallback(contentsOpenedCallback);
    }
};

final private ResultCallback<DriveApi.DriveContentsResult> contentsOpenedCallback = new ResultCallback<DriveApi.DriveContentsResult>() {

    @Override
    public void onResult(DriveApi.DriveContentsResult result) {

        if (!result.getStatus().isSuccess()) {
            Log.v(TAG, "Error opening file");
            return;
        }

        try {
            FileInputStream is = new FileInputStream(getDbPath());
            BufferedInputStream in = new BufferedInputStream(is);
            byte[] buffer = new byte[8 * 1024];
            DriveContents content = result.getDriveContents();
            BufferedOutputStream out = new BufferedOutputStream(content.getOutputStream());
            int n = 0;
            while( ( n = in.read(buffer) ) > 0 ) {
                out.write(buffer, 0, n);
            }

            in.close();
commitAndCloseContents is DEPRECATED -->/**mfile.commitAndCloseContents(api, content).setResultCallback(new ResultCallback<Status>() {   
                @Override
                public void onResult(Status result) {
                    // Handle the response status
                }
            });**/
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

};

private File getDbPath() {
    return this.getDatabasePath(DATABASE_NAME);
}

@Override
public void onConnectionSuspended(int cause) {
    // TODO Auto-generated method stub
    Log.v(TAG, "Connection suspended");

}

public void onDialogDismissed() {
    mResolvingError = false;
}

public static class ErrorDialogFragment extends DialogFragment {
    public ErrorDialogFragment() {}

    public Dialog onCreateDialog(Bundle savedInstanceState) {
        int errorCode = this.getArguments().getInt("error");
        return GooglePlayServicesUtil.getErrorDialog(errorCode, this.getActivity(), DIALOG_ERROR_CODE);
    }

    public void onDismiss(DialogInterface dialog) {
        ((ExpectoPatronum) getActivity()).onDialogDismissed();
    }
}
}
15
Cytus

Googleドライブへのアクセスに使用される両方のAPIは、バイナリコンテンツを処理します。したがって、バイナリDBファイルをアップロードし、適切なMIMEタイプと名前(タイトル)を指定するだけです。
APIの選択はユーザーによって異なります [〜#〜] gdaa [〜#〜] アップロード/ダウンロードがGoogle Play開発者サービスで処理される「ローカル」エンティティのように動作します- [〜#〜] rest [〜#〜] APIはより低レベルであり、より細かく制御できますが、ネットワークの問題(wifiのオン/オフなど)に注意する必要があります。つまり、通常そのための同期サービスを構築します。 GDAAでは、GooPlaySvcsによって自動的に行われます。しかし、私は余談です。
私はこれを指摘することができます GitHubデモ 、かなり最近(GooPlaySvcs 7.00。+)、さまざまなREST/GDAAの問題をテストするために使用します。 MainActivityは、さまざまなGoogleアカウント間の切り替えを可能にするという事実により少し複雑ですが、 これらのハードル を通過する場合、RESTまたはGDAA CRUDのいずれかを使用できますラッパー。

この行 を見てください。 byte []バッファーにはバイナリJPEGデータが含まれており、「image/jpeg」MIMEタイプ(および時間ベースの名前)に対応しています。次のような構成を使用して、DBファイルをbyte []バッファーにロードするだけの場合に実行する必要があります。

  private static final int BUF_SZ = 4096;

  static byte[] file2Bytes(File file) {
    if (file != null) try {
       return is2Bytes(new FileInputStream(file));
    } catch (Exception ignore) {}
   return null;
  }

  static byte[] is2Bytes(InputStream is) {
    byte[] buf = null;
    BufferedInputStream bufIS = null;
    if (is != null) try {
      ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
      bufIS = new BufferedInputStream(is);
      buf = new byte[BUF_SZ];
      int cnt;
      while ((cnt = bufIS.read(buf)) >= 0) {
        byteBuffer.write(buf, 0, cnt);
      }
      buf = byteBuffer.size() > 0 ? byteBuffer.toByteArray() : null;
    } catch (Exception e) {le(e);}
    finally {
      try {
        if (bufIS != null) bufIS.close();
      } catch (Exception e) {le(e);}
    }
    return buf;
  }

今はSQLite DBのMIMEタイプを覚えていませんが、正確に一度だけ実行したのでそれができると確信しています(残念ながら、コードはもうなくなっています)。そして、私は実際にいくつかのWebアプリを使用してSQLite DBに「クラウドで」アクセスし、変更することができたことを覚えています。

幸運を

UPDATE:
私が上に怒りを書いた後、私はあなたが話しているデモを見ました。それが機能している場合、最も簡単な方法は実際にDBファイルを正しくプラグインすることです ここ 、正しいMIMEを設定すれば問題ありません。選んでください。
そして「非推奨」の問題に対処します。 GDAAはまだ開発中で、クイックスタートは1年以上前です。それが私たちが住んでいる世界です:-)

6
seanpj

非推奨のコードを次のコードに置き換える必要があります。
contents.commit(api、null);

https://developer.Android.com/reference/com/google/Android/gms/drive/DriveContents.html を参照してください

1
Ofir