Rome_Leader
Rome_Leader

Reputation: 2700

Concurrency Issues with Google Drive API on Android

I'm having some trouble integrating the Google Drive API into my Android app. Basically, I'm trying to create a folder in which to store my error logs. The problem is that occasionally, the thread will run, and the folder won't be created by the time the file needs to be created, and so the app crashes. I'm trying to think about how to avoid this scenario, and have tried a few methods so far, including making the folder assignment in the folder callback, but all to no avail. I sometimes get lucky (particularly when debugging, unfortunately) and the file saves OK, but I obviously need to resolve the concurrency issue. Please let me know if any more code is needed for context.

protected void onPause() {
    // TODO Find the right place for this
    if (!mDriveLogList.isEmpty()) {
        // Perform I/O off the UI thread.
        // TODO Fix to use RxJava
        new Thread() {
            @Override
            public void run() {
                Timber.i("Starting File Creation");
                // write content to DriveContents
                if (mDriveContents == null) {
                    Timber.e("Drive Contents Were Null");

                } else {
                    OutputStream outputStream = mDriveContents.getOutputStream();
                    Writer writer = new OutputStreamWriter(outputStream);
                    //TODO Clean/Refactor
                    try {
                        writer.write("Status Log For: " + DateHelper.getDate() + "\n");
                        for (String logEntry : mDriveLogList) {
                            writer.write(logEntry + "\n");
                        }
                        writer.close();
                    } catch (IOException e) {
                        Timber.e(e, "Error During Drive Contents Callback");
                    }

                    MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                            .setTitle(SURVEIL_DROID + " " + DateHelper.getDate())
                            .setMimeType("text/plain")
                            .setStarred(true).build();

                    MetadataChangeSet folderSet = new MetadataChangeSet.Builder()
                            .setTitle("SurveilCustomFolder")
                            .build();

                    Drive.DriveApi.getRootFolder(mGoogleApiClient)
                            .createFolder(mGoogleApiClient, folderSet)
                            .setResultCallback(folderCallback);

                        mDriveFolder = mFolderId.asDriveFolder();

                        mDriveFolder.createFile(mGoogleApiClient, changeSet, mDriveContents)
                                .setResultCallback(fileCallback);

                    mDriveLogList.clear();
                }
            }
        }.start();

Upvotes: 0

Views: 213

Answers (2)

Anatoli
Anatoli

Reputation: 101

createFolder() returns a PendingResult, you can use one of the await() methods of the PendingResult to block until the folder is created. See here: (https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html#await())

Upvotes: 0

JohnWowUs
JohnWowUs

Reputation: 3083

You could use a countdownlatch (See https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html) to help with the synchronization. Something like

protected void onPause() {
    // TODO Find the right place for this
    if (!mDriveLogList.isEmpty()) {

        // Perform I/O off the UI thread.
        // TODO Fix to use RxJava
        new Thread() {
            @Override
            public void run() {
                final protected CountDownLatch connectionLatch = new CountDownLatch(1);
                protected boolean folderCreated = false;                
                Timber.i("Starting File Creation");
                // write content to DriveContents
                if (mDriveContents == null) {
                    Timber.e("Drive Contents Were Null");

                } else {
                    OutputStream outputStream = mDriveContents.getOutputStream();
                    Writer writer = new OutputStreamWriter(outputStream);
                    //TODO Clean/Refactor
                    try {
                        writer.write("Status Log For: " + DateHelper.getDate() + "\n");
                        for (String logEntry : mDriveLogList) {
                            writer.write(logEntry + "\n");
                        }
                        writer.close();
                    } catch (IOException e) {
                        Timber.e(e, "Error During Drive Contents Callback");
                    }

                    MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
                            .setTitle(SURVEIL_DROID + " " + DateHelper.getDate())
                            .setMimeType("text/plain")
                            .setStarred(true).build();

                    MetadataChangeSet folderSet = new MetadataChangeSet.Builder()
                            .setTitle("SurveilCustomFolder")
                            .build();

                    Drive.DriveApi.getRootFolder(mGoogleApiClient)
                            .createFolder(mGoogleApiClient, folderSet)
                            .setResultCallback(new
                                ResultCallback<DriveFolderResult>() {
                                    @Override
                                    public void onResult(DriveFolderResult result) {
                                       folderCreated = result.getStatus().isSuccess();
                                       connectionLatch.countDown(); // Release latch                                  
                                    }
                                });
                    try {
                        connectionLatch.await() ;
                    } catch (InterruptedException e) {              
                        e.printStackTrace();
                        return;
                    }
                    if (folderCreated) {
                        mDriveFolder = mFolderId.asDriveFolder();
                        mDriveFolder.createFile(mGoogleApiClient, changeSet, mDriveContents)
                                    .setResultCallback(fileCallback);                        
                        mDriveLogList.clear();
                    }
                }
            }
        }.start();  
    }
}

should work.

Upvotes: 1

Related Questions