File written using ACTION_CREATE_DOCUMENT is empty on Google Drive but not local storage

The comment from @greenapps put me on the right path. Changing it to use getContentResolver().openOutputStream(...) fixed the problem:

try {
    OutputStream os = c.getContentResolver().openOutputStream(uri);
    if( os != null ) {
        os.write(data.getBytes());
        os.close();
    }
}
catch(IOException e) {
    e.printStackTrace();
}

Update: After awhile of using this in my app, the problem re-occurred (files written to Google Drive were 0 bytes, but could be written locally). Clearing the cache data for my app solved it again.


Refer to official documentation at https://developer.android.com/guide/topics/providers/document-provider

On Android 4.3 and lower, if you want your app to retrieve a file from another app, it must invoke an intent such as ACTION_PICK or ACTION_GET_CONTENT. The user must then select a single app from which to pick a file and the selected app must provide a user interface for the user to browse and pick from the available files.

On Android 4.4 (API level 19) and higher, you have the additional option of using the ACTION_OPEN_DOCUMENT intent, which displays a system-controlled picker UI controlled that allows the user to browse all files that other apps have made available. From this single UI, the user can pick a file from any of the supported apps.

On Android 5.0 (API level 21) and higher, you can also use the ACTION_OPEN_DOCUMENT_TREE intent, which allows the user to choose a directory for a client app to access.

For me the following solution works perfect for both local as well as google drive on Android 9

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK && data != null) {
        if (requestCode == REQUEST_SAVE_File) {
            try {
                stream = getContentResolver().openOutputStream(data.getData());
                ((BitmapDrawable) imageView.getDrawable()).getBitmap().compress(Bitmap.CompressFormat.PNG, 100, stream);
                strem.close(); ///very important
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
}

And intent is created as follows

    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("image/png");
    intent.putExtra(Intent.EXTRA_TITLE, "my-image.png");

    startActivityForResult(intent, REQUEST_SAVE_FILE);

Make sure you close the stream after writing. Otherwise file may not be saved.