Saving an image after getting folder from Storage

2019-05-31 15:04发布

问题:

I set a preference for users to select save folder for my app using Storage Access Framework. After getting uri onActivityResult I save it to SharedPreferences as String and save image when it's to be saved.

I'm using this method to save image successfully.

public void saveImageWithDocumentFile(String uriString, String mimeType, String name) {
    isImageSaved = false;
    try {
        Uri uri = Uri.parse(uriString);
        DocumentFile pickedDir = DocumentFile.fromTreeUri(this, uri);
        DocumentFile file = pickedDir.createFile(mimeType, name);
        OutputStream out = getContentResolver().openOutputStream(file.getUri());
        isImageSaved = mBitmap.compress(CompressFormat.JPEG, 100, out);
        out.close();

    } catch (IOException e) {
        throw new RuntimeException("Something went wrong : " + e.getMessage(), e);
    }
    Toast.makeText(MainActivity.this, "Image saved  " + isImageSaved, Toast.LENGTH_SHORT).show();
}

If user deletes the folder selected using SAF, iget null DocumentFile file and app crashes. My first question is how can i check if folder exist without opening SAF ui again.

I also want to use ParcelFileDescriptor to save same image with this method

public void saveImageWithParcelFileDescriptor(String folder, String name) {
    if (mBitmap == null) {
        Toast.makeText(MainActivity.this, "", Toast.LENGTH_SHORT).show();
        return;
    }
    String image = folder + File.separator + name + ".jpg";
    Toast.makeText(MainActivity.this, "image " + image, Toast.LENGTH_LONG).show();

    Uri uri = Uri.parse(image);
    ParcelFileDescriptor pfd = null;
    FileOutputStream fileOutputStream = null;
    try {
        pfd = getContentResolver().openFileDescriptor(uri, "w");
        fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
        mBitmap.compress(CompressFormat.JPEG, 100, fileOutputStream);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (pfd != null) {
            try {
                pfd.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (fileOutputStream != null) {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    Toast.makeText(MainActivity.this, "Image saved  " + isImageSaved, Toast.LENGTH_SHORT).show();

}

i get java.lang.IllegalArgumentException: Invalid URI: content://com.android.externalstorage.documents/tree/612E-B7BF%3Aname/imagePFD.jpg on linepfd = getContentResolver().openFileDescriptor(uri, "w");

This is how I call this method, currentFolder is the folder I get using intent and same folder on first method.

saveImageWithParcelFileDescriptor(currentFolder, "imagePFD");

How can I fix this, and which method is more preferable and why?

回答1:

how can i check if folder exist

DocumentFile has an exists() method. In theory, pickedDir.exists() should tell you if it exists. In practice, it is up to the storage provider.

I also want to use ParcelFileDescriptor to save same image with this method

That code has bugs:

  • You cannot grant yourself permissions using grantUriPermission()

  • You cannot invent arbitrary Uri values via concatenation, particularly for a provider that is not yours

How can I fix this

Delete it.

which method is more preferable

The first one.

and why?

The first one will work, perhaps with minor adjustment. The second one has no chance of working.