问题描述
我已经成功在SD卡上创建了我的数据库备份并从那里恢复,但意识到我备份的目的是为了确保数据的安全,并且在这种情况下,如果物理设备本身已损坏,丢失或自发燃烧,SD卡上的备份也会如此。因此,在这种情况下将备份放在与原始位置相同的位置,非常坦率地违反了备份的目的。
因此,我认为使用Google Drive更安全保留数据库文件的地方,它是免费的。我已经仔细查看了Google的演示,我的工作很好。但我仍然不知道如何为我的情况做到这一点。
我发现了一些代码来摆弄,但它仍然使用一些废弃的方法,到目前为止,我只设法运行它时省略弃用的区域,但它只在我的Google云端硬盘中创建一个空白的二进制文件,所以我认为已弃用的区域是它实际上传数据库备份内容的地方。如果任何人都可以提供帮助,我将不胜感激。
我会把它放在下面,以便任何人都可以用它来更好地向我解释事情。
public class ExpectoPatronum extends Activity实现了ConnectionCallbacks,OnConnectionFailedListener {
private static final String TAG =MainActivity;
私有GoogleApiClient api;
private boolean mResolvingError = false;
私人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);
//创建Drive API实例
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(); //将客户端连接到Google Drive
$ b @Override
public void onStop(){
super.onStop();
api.disconnect(); //断开客户端与Google Drive的连接
$ b @Override
public void onConnectionFailed(ConnectionResult result){
Log.v(TAG,Connection failed) ;
if(mResolvingError){//如果已处于解析状态,则返回。
return;
} else if(result.hasResolution()){//错误可以通过用户交互开始一个intent来解决
mResolvingError = true;
尝试{
result.startResolutionForResult(this,DIALOG_ERROR_CODE);
} catch(SendIntentException e){
e.printStackTrace();
}
} else {//错误无法解析。显示错误对话框,如果可能的话说明原因。
ErrorDialogFragment fragment = new ErrorDialogFragment();
Bundle args = new Bundle();
args.putInt(error,result.getErrorCode());
fragment.setArguments(args);
fragment.show(getFragmentManager(),errordialog);
$ b @Override
public void onActivityResult(int requestCode,int resultCode,Intent data){
if(requestCode == DIALOG_ERROR_CODE){
mResolvingError = false;
if(resultCode == RESULT_OK){//错误已解决,现在连接到客户端,如果不这样做。
if(!api.isConnecting()&&!api.isConnected()){
api.connect();
}
}
}
}
@Override
public void onConnected(Bundle connectionHint){
Log.v TAG,连接成功);
/ *建立与Google云端硬盘的连线。现在请求Content实例,它可以用来提供文件内容。
回调注册相同。 * /
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,尝试创建新文件内容时出错);
return;
}
String mimeType = MimeTypeMap.getSingleton()。getExtensionFromMimeType(db);
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle(GOOGLE_DRIVE_FILE_NAME)// Google Drive文件名
.setMimeType(mimeType)
.setStarred(true).build() ;
//在根文件夹中创建文件
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,尝试创建文件时出错);
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,打开文件时出错);
return;
}
尝试{
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; ((n = in.read(buffer))> 0){
out.write(buffer,0,n);
}
in.close();
commitAndCloseContents DEPRECATED - > / ** mfile.commitAndCloseContents(api,content).setResultCallback(new ResultCallback< Status>(){
@Override
public void onResult(Status result) {
//处理响应状态
}
}); ** /
} catch(FileNotFoundException e){
// TODO自动生成的catch块
e.printStackTrace();
} catch(IOException e){
// TODO自动生成的catch块
e.printStackTrace();
}
}
};
私有文件getDbPath(){
返回this.getDatabasePath(DATABASE_NAME);
}
@Override
public void onConnectionSuspended(int cause){
// TODO自动生成的方法存根
Log.v(TAG,连接暂停);
}
public void onDialogDismissed(){
mResolvingError = false;
$ b $ public static class class ErrorDialogFragment extends DialogFragment {
public ErrorDialogFragment(){}
$ b $ public Dialog onCreateDialog(Bundle savedInstanceState){
int errorCode = this.getArguments()。getInt(error);
返回GooglePlayServicesUtil.getErrorDialog(errorCode,this.getActivity(),DIALOG_ERROR_CODE);
$ b $ public void onDismiss(DialogInterface dialog){
((ExpectoPatronum)getActivity())。onDialogDismissed();
用于访问Google Drive的两个API均处理二进制内容。所以你唯一要做的就是上传你的二进制数据库文件,给它一个合适的MIME类型和一个名称(标题)。
API的选择取决于你,的行为类似于由Google Play服务处理上传/下载的本地实体, Api是更低层次的,给你更多的控制权,但你必须关心网络问题(无线开/关等),即你通常必须建立一个同步服务来做到这一点。借助GDAA,GooPlaySvcs为您完成。但是我离题了。
我可以指点你这个,相当新近(GooPlaySvcs 7.00。+),我用它来测试不同的REST / GDAA问题。
MainActivity有点复杂,因为它允许在不同的Google帐户之间切换,但是如果您通过,您可以使用REST或GDAA CRUD包装。
请看。 byte []缓冲区包含二进制JPEG数据,并且它与image / jpegMIME类型(以及基于时间的名称)一起使用。你必须做的唯一事情就是使用这样的结构将你的数据库文件加载到byte []缓冲区中: static final int BUF_SZ = 4096;
$ b $ 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 =新字节[BUF_SZ];
int cnt; ((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数据库'在云中'。
好运
更新:
在我写上面的咆哮之后,我看了一下你正在谈论的演示。如果你有它的工作,最简单的方法实际上是插入你的数据库文件正确,设置正确的MIME,你很好走。带你选择。
并解决你的'弃用'问题。 GDAA仍在开发中,快速启动已经超过一年。这就是我们生活的世界:-)
I've managed to create a backup of my database on an SD card and restore from there but realized that the purpose of my backup is to ensure the safety of the data and in this case if the physical device itself is damaged, lost, or spontaneously combusts so will the backup on the SD card. So having the backup in the same place as the original in this case, quite frankly defeats the purpose of having a backup.
So I thought of using Google Drive as a safer place to keep the db file, that and it's free. I've taken a peek into Google's quickstart demo which I got working just fine. But I still have no idea how to get this done for my case.
I've found some code to fiddle with but it's still using some deprecated methods and so far I've only managed to run it when omitting the deprecated area but it only creates a blank binary file in my Google Drive so I think that deprecated area is where it actually uploads the DB backup content. If anyone could help out that would be greatly appreciated.
I'll leave it down below in case anyone can use it to explain things to me better. I've also marked the deprecated method below, it's near the end.
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();
}
}
}
Both APIs used to access Google Drive deal with a binary content. So the only thing you have to do is to upload your binary DB file, give it a proper MIME type and a NAME (title).
The selection of API depends on you, GDAA behaves like a 'local' entity with uploads / downloads handled by Google Play Services, REST Api is more low-level, giving you more control, but you have to take care of networking issues (wifi on/off, etc), i.e. you usually have to build a sync service to do so. With GDAA it is done for you by GooPlaySvcs. But I digress.
I can point you to this GitHub demo, fairly recent (GooPlaySvcs 7.00.+), I use to test different REST / GDAA issues.The MainActivity is a bit complicated by the fact that it allows for switching between different Google accounts, but if you get through these hurdles, you can use either REST or GDAA CRUD wrappers.
Take look at this line. The byte[] buffer contains binary JPEG data and it goes with "image/jpeg" mime type (and a time-based name). The only thing you have to do if is load your DB file into a byte[] buffer using a construct like this:
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;
}
I don't remember the MIME type for SQLite DB now, but I am sure it can be done since I was doing exactly that once (the code is gone now, unfortunately). And I remember I could actually access and modify the SQLite DB 'up in the cloud' using some web app.
Good Luck
UPDATE:
After I wrote the rant above I looked at the demo you're talking about. If you have it working, the easiest way is actually to plug your DB file right here, set the correct MIME and you're good to go. Take you pick.
And to address your 'deprecated' issue. GDAA is still being developed and the quickstart is over a year old. That's the world we live in :-)
这篇关于使用Google Drive备份和恢复SQLite数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!