How to sync SQLite database with Google Drive for cloud backup

I successfully created a backup system for my SQLite database that saves to SD card storage. However, I realized this approach has a major flaw. If my phone gets lost, broken, or damaged, the backup stored on the SD card will be gone too. This makes the whole backup strategy pointless since both the original data and backup are on the same device.

I want to use Google Drive for cloud storage instead since it’s secure and free. I looked at Google’s official quickstart guide and got the basic demo working. But I’m stuck on how to adapt it for my database backup needs.

I found some sample code online but it uses old deprecated methods. When I remove the deprecated parts, the code runs but only creates an empty file on Google Drive. I think the deprecated section was responsible for actually uploading the database content.

Here’s my current code attempt:

public class CloudBackupManager extends Activity implements ConnectionCallbacks, OnConnectionFailedListener {

    private static final String TAG = "CloudBackup";
    private GoogleApiClient client;
    private boolean isResolvingError = false;
    private DriveFile backupFile;
    private static final int ERROR_DIALOG_ID = 200;
    private static final String DB_NAME = "userdata";
    private static final String BACKUP_FILE_NAME = "database_backup";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        client = new GoogleApiClient.Builder(this)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }

    @Override
    public void onStart() {
        super.onStart();
        if(!isResolvingError) {
            client.connect();
        }
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.d(TAG, "Successfully connected to Drive");
        Drive.DriveApi.newDriveContents(client).setResultCallback(driveContentsCallback);
    }

    final private ResultCallback<DriveApi.DriveContentsResult> driveContentsCallback = new ResultCallback<DriveApi.DriveContentsResult>() {
        @Override
        public void onResult(DriveApi.DriveContentsResult result) {
            if (!result.getStatus().isSuccess()) {
                Log.e(TAG, "Failed to create drive contents");
                return;
            }

            String fileType = MimeTypeMap.getSingleton().getExtensionFromMimeType("db");
            MetadataChangeSet metadata = new MetadataChangeSet.Builder()
                    .setTitle(BACKUP_FILE_NAME)
                    .setMimeType(fileType)
                    .setStarred(true)
                    .build();
                    
            Drive.DriveApi.getRootFolder(client)
                    .createFile(client, metadata, result.getDriveContents())
                    .setResultCallback(fileCreatedCallback);
        }
    };

    final private ResultCallback<DriveFileResult> fileCreatedCallback = new ResultCallback<DriveFileResult>() {
        @Override
        public void onResult(DriveFileResult result) {
            if (!result.getStatus().isSuccess()) {
                Log.e(TAG, "File creation failed");
                return;
            }
            backupFile = result.getDriveFile();
            backupFile.open(client, DriveFile.MODE_WRITE_ONLY, null).setResultCallback(fileOpenCallback);
        }
    };

    final private ResultCallback<DriveApi.DriveContentsResult> fileOpenCallback = new ResultCallback<DriveApi.DriveContentsResult>() {
        @Override
        public void onResult(DriveApi.DriveContentsResult result) {
            if (!result.getStatus().isSuccess()) {
                Log.e(TAG, "Cannot open file for writing");
                return;
            }

            try {
                FileInputStream inputStream = new FileInputStream(getDatabaseFile());
                BufferedInputStream bufferedInput = new BufferedInputStream(inputStream);
                byte[] dataBuffer = new byte[8 * 1024];
                DriveContents driveContent = result.getDriveContents();
                BufferedOutputStream bufferedOutput = new BufferedOutputStream(driveContent.getOutputStream());
                int bytesRead = 0;
                while((bytesRead = bufferedInput.read(dataBuffer)) > 0) {
                    bufferedOutput.write(dataBuffer, 0, bytesRead);
                }
                bufferedInput.close();
                
                // THIS METHOD IS DEPRECATED - Need modern alternative
                /*
                backupFile.commitAndCloseContents(client, driveContent).setResultCallback(new ResultCallback<Status>() {
                    @Override
                    public void onResult(Status status) {
                        // Handle upload completion
                    }
                });
                */
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    private File getDatabaseFile() {
        return this.getDatabasePath(DB_NAME);
    }

    @Override
    public void onConnectionSuspended(int cause) {
        Log.w(TAG, "Drive connection suspended");
    }
}

Can someone help me replace the deprecated commitAndCloseContents method with the current approach? I need to actually upload the database file content to Google Drive successfully.

Just went through this nightmare myself - you need to close the outputstream and call driveContent.commit() instead of that old method. After your bufferedOutput.write loop, add bufferedOutput.close() then driveContent.commit(client, null).setResultCallback(…). That’ll actually save the db file content instead of creating empty files. Also check your mime type - should be “application/x-sqlite3” not using getExtensionFromMimeType like that.

The Google Drive Android API you’re using got completely discontinued. I switched to the Drive REST API v3 two years ago when I ran into this same problem. You’ll need to rebuild your whole approach - those DriveContents and callback patterns are gone. Now you authenticate through GoogleSignInClient, grab an access token, then make HTTP requests to the Drive REST endpoints. To upload your SQLite file, just POST to https://www.googleapis.com/upload/drive/v3/files with a multipart request containing your database file. The auth setup’s more complex but file operations are just straightforward HTTP calls. Google’s Drive API docs have solid examples for the REST approach, though migrating from your current code will be a pain.

That Google Drive Android API got completely deprecated in December 2019. Hit the same wall last year with an old backup app I was maintaining. GoogleApiClient is dead - won’t work with newer Play Services versions. You’ve gotta migrate to Drive REST API v3 with the newer Google Sign-In library. It’s pretty different - no more DriveContents or callbacks. You’re doing HTTP requests through the Drive service client now. Basic flow: authenticate with GoogleSignIn, grab credentials, then use Drive service to upload files directly. Google’s migration docs helped me out, but you’re basically rewriting most of your code structure. Once you get through the initial setup pain, it’s actually cleaner than the old way. Don’t forget to enable Drive API in Google Cloud Console and set up OAuth consent properly.