Reputation: 1550
I am trying to upload a sqlite database file to dropbox. This is my code:
public void uploadDb(){
File public_db_file = null;
try {
public_db_file = writeDbToPublicDirectory();
} catch (IOException e2) {
e2.printStackTrace();
}
DbxFileSystem dbxFs = null;
try {
dbxFs = DbxFileSystem.forAccount(mAccount);
} catch (Unauthorized e1) {
e1.printStackTrace();
}
DbxFile testFile = null;
try {
testFile = dbxFs.create(new DbxPath("database_sync.txt"));
} catch (InvalidPathException e1) {
e1.printStackTrace();
} catch (DbxException e1) {
e1.printStackTrace();
}
try {
testFile.writeFromExistingFile(public_db_file, false);
} catch (IOException e) {
e.printStackTrace();
} finally {
testFile.close();
}
}
EDIT (More code)
This function copies my database from the app private dir to a public dir so that I can upload it:
private File writeDbToPublicDirectory() throws IOException {
// TODO Auto-generated method stub
File sd = Environment.getExternalStorageDirectory();
File backupDB = null;
if (sd.canWrite()) {
String backupDBPath = "copied_database.db";
File currentDB = context.getDatabasePath("private_database");
backupDB = new File(sd, backupDBPath);
if (currentDB.exists()) {
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
}
}
return backupDB;
}
The problem is that when I check on my device dropbox, the file size is 0 bytes. The file is created on dropbox, but my database data is not. What am I doing wrong? Thank you in advance
EDIT
I have decided that using Google Drive may be a better option, but I can only upload text files by using the sample applications. Is there any good tutorial or resource that I can use to upload a sqlite database file? I am really badly stuck on this. Please help me with either of these, thank you in advance
Upvotes: 2
Views: 6464
Reputation: 803
I modified @Manish Mulimani's code. I make use of some modules in com.google.android.gms.drive.sample.demo which is available from Google Drive API Website. The modules are BaseDemoActivity, ApiClientAsyncTask and EditContentsActivity. Here are the code.
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.webkit.MimeTypeMap;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveApi;
import com.google.android.gms.drive.DriveContents;
import com.google.android.gms.drive.DriveFile;
import com.google.android.gms.drive.DriveFolder;
import com.google.android.gms.drive.MetadataChangeSet;
import com.google.android.gms.drive.DriveApi.DriveContentsResult;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class gDriveActivity extends BaseDemoActivity {
private final static String TAG = "gDriveActivity";
@Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
// create new contents resource.
Drive.DriveApi.newDriveContents(getGoogleApiClient()).setResultCallback(driveContentsCallback);
}
final private ResultCallback<DriveApi.DriveContentsResult> driveContentsCallback =
new ResultCallback<DriveApi.DriveContentsResult>() {
@Override
public void onResult(DriveApi.DriveContentsResult result) {
if (!result.getStatus().isSuccess()) {
//if failure
showMessage("Error while trying to create new file contents");
return;
}
//change the metadata of the file. by setting title, setMimeType.
String mimeType = MimeTypeMap.getSingleton().getExtensionFromMimeType("db");
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("mydb")
.setMimeType(mimeType)
.build();
Drive.DriveApi.getAppFolder(getGoogleApiClient())
.createFile(getGoogleApiClient(), changeSet, result.getDriveContents()).setResultCallback(fileCallBack);
}
};
final ResultCallback<DriveFolder.DriveFileResult> fileCallBack = new ResultCallback<DriveFolder.DriveFileResult>() {
@Override
public void onResult(DriveFolder.DriveFileResult driveFileResult) {
if (!driveFileResult.getStatus().isSuccess()) {
Log.v(TAG, "Error while trying to create the file");
return;
}
//Initialize mFile to be processed in AsyncTask
DriveFile mfile = driveFileResult.getDriveFile();
new EditContentsAsyncTask(gDriveActivity .this).execute(mfile);
}
};
public class EditContentsAsyncTask extends ApiClientAsyncTask<DriveFile, Void, Boolean> {
public EditContentsAsyncTask(Context context) {
super(context);
}
@Override
protected Boolean doInBackgroundConnected(DriveFile... args) {
DriveFile file = args[0];
try {
DriveContentsResult driveContentsResult = file.open(
getGoogleApiClient(), DriveFile.MODE_WRITE_ONLY, null).await();
if (!driveContentsResult.getStatus().isSuccess()) {
return false;
}
DriveContents driveContents = driveContentsResult.getDriveContents();
//edit the outputStream
DatabaseHandler db = new DatabaseHandler(gDriveActivity .this);
String inFileName = getApplicationContext().getDatabasePath(db.getDatabaseName()).getPath();
FileInputStream is = new FileInputStream(inFileName);
BufferedInputStream in = new BufferedInputStream(is);
byte[] buffer = new byte[8 * 1024];
BufferedOutputStream out = new BufferedOutputStream(driveContents.getOutputStream());
int n = 0;
while ((n = in.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
in.close();
com.google.android.gms.common.api.Status status =
driveContents.commit(getGoogleApiClient(), null).await();
return status.getStatus().isSuccess();
} catch (IOException e) {
Log.e(TAG, "IOException while appending to the output stream", e);
}
return false;
}
@Override
protected void onPostExecute(Boolean result) {
if (!result) {
showMessage("Error while editing contents");
return;
}
showMessage("Successfully edited contents");
}
}
}
Upvotes: 3
Reputation: 17615
I was able to backup the database using Google Drive API. I have used the byte array to copy the contents. Following is the Activity code, which creates a new file on Google Drive root folder and copies the sqlite db content. I've added comments wherever required. Let me know whether it helps.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.drive.Contents;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveFile;
import com.google.android.gms.drive.DriveApi.ContentsResult;
import com.google.android.gms.drive.DriveFolder.DriveFileResult;
import com.google.android.gms.drive.MetadataChangeSet;
import android.app.Activity;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.webkit.MimeTypeMap;
public class MainActivity 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 = "person.db";
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.newContents(api).setResultCallback(contentsCallback);
}
final private ResultCallback<ContentsResult> contentsCallback = new ResultCallback<ContentsResult>() {
@Override
public void onResult(ContentsResult 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.getContents())
.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.openContents(api, DriveFile.MODE_WRITE_ONLY, null).setResultCallback(contentsOpenedCallback);
}
};
final private ResultCallback<ContentsResult> contentsOpenedCallback = new ResultCallback<ContentsResult>() {
@Override
public void onResult(ContentsResult 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];
Contents content = result.getContents();
BufferedOutputStream out = new BufferedOutputStream(content.getOutputStream());
int n = 0;
while( ( n = in.read(buffer) ) > 0 ) {
out.write(buffer, 0, n);
}
in.close();
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) {
((MainActivity) getActivity()).onDialogDismissed();
}
}
}
Upvotes: 11
Reputation: 2547
I think you could use the Storage API
https://developer.android.com/guide/topics/providers/document-provider.html
A useful tutorial on
http://www.techotopia.com/index.php/An_Android_Storage_Access_Framework_Example
Upvotes: 2