使用 ACTION_CREATE_DOCUMENT 写入的文件在 Google Drive 上是空的,但不是本地存储

Tyl*_*r V 13 android android-intent google-drive-api

我有一个应用程序,它使用ACTION_CREATE_DOCUMENT意图获取要写入的 Uri 来导出 CSV 文件。这在一段时间内运行良好,但最近当我去保存文件并选择 Google Drive 时,我注意到生成的文件是空的(0 字节)。但是,如果我选择“下载”文件夹作为目标(本地存储),则会正确创建并写入文件。

保存到 Google Drive 的结果(正确写入的文件为 14 字节)

我将问题浓缩为一个简单的测试活动(如下)并验证代码的所有部分实际上都在执行(没有捕获异常,ParcelFileDescriptor不为空,等等)。

我在 Android 7 和 8 模拟器以及 Android 8 物理设备上对此进行了测试,并且都显示出相同的行为,但是旧的 Android 5 手机运行正常(??)。

该应用程序的完整版本具有并正确请求读取和写入外部存储权限以处理某些第三方文件管理器,但 Google 云端硬盘不需要这些权限,因此我在此示例中省略了它(行为与授予的权限)。

我得到的 uri 看起来像一个有效的内容 uri ( content://com.google.android.apps.docs.storage/document/acc%3...)

有没有其他人看到过这个问题?我在这里做错了吗?我怎样才能再次使用 Google Drive 进行这项工作?

public class MainActivity extends AppCompatActivity {

    private static final int FILE_EXPORT_REQUEST_CODE = 12;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (resultCode != RESULT_OK)
            return;

        switch(requestCode) {
            case FILE_EXPORT_REQUEST_CODE:
                if( data != null ) {
                    Uri uri = data.getData();
                    if( uri != null ) {
                        new ExportCSV(this).execute(uri);
                    }
                }
                break;
        }
    }

    // test Activity has a single button that calls this
    public void saveFile(View v) {
        Intent exportIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        exportIntent.addCategory(Intent.CATEGORY_OPENABLE);
        exportIntent.setType("text/csv");
        String filename = "test.csv";
        exportIntent.putExtra(Intent.EXTRA_TITLE, filename);
        startActivityForResult(exportIntent, FILE_EXPORT_REQUEST_CODE);
    }

    private static class ExportCSV extends AsyncTask<Uri, Void, Boolean> {
        private final WeakReference<Context> context;

        ExportCSV(Context c) {
            context = new WeakReference<>(c);
        }

        @Override
        protected Boolean doInBackground(Uri... uris) {
            Uri uri = uris[0];
            Context c = context.get();

            if( c == null ) {
                return false;
            }

            String data = "colA,colB\n1,2\n";
            boolean success = false;

            try {
                ParcelFileDescriptor pfd = c.getContentResolver().openFileDescriptor(uri, "w");
                if( pfd != null ) {
                    FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
                    fileOutputStream.write(data.getBytes());
                    fileOutputStream.close();
                    success = true;
                }
            }
            catch(Exception e) {
                e.printStackTrace();
            }
            return success;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Tyl*_*r V 9

@greenapps 的评论让我走上了正确的道路。将其更改为使用getContentResolver().openOutputStream(...)解决了问题:

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

更新:在我的应用程序中使用它一段时间后,问题再次出现(写入 Google Drive 的文件为 0 字节,但可以在本地写入)。清除我的应用程序的缓存数据再次解决了它。