在奇巧(或新画廊)之前,意图。ACTION_GET_CONTENT返回一个这样的URI

内容:/ /媒体/外部/图片/媒体/ 3951。

使用ContentResolver并查询 media . data返回文件URL。

然而,在奇巧,画廊返回一个URI(通过“Last”)像这样:

内容:/ / com.android.providers.media.documents /文档/图片:3951

我该怎么处理呢?


当前回答

This is what I do: Uri selectedImageURI = data.getData(); imageFile = new File(getRealPathFromURI(selectedImageURI)); private String getRealPathFromURI(Uri contentURI) { Cursor cursor = getContentResolver().query(contentURI, null, null, null, null); if (cursor == null) { // Source is Dropbox or other similar local file path return contentURI.getPath(); } else { cursor.moveToFirst(); int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); return cursor.getString(idx); } } NOTE: managedQuery() method is deprecated, so I am not using it.

这个答案是来自m3n0R的问题安卓得到真正的路径Uri.getPath()和我声称没有信用。我只是想那些还没有解决这个问题的人可以使用这个。

其他回答

我相信已经发布的回复应该会让人们朝着正确的方向前进。然而,以下是我所做的对我正在更新的遗留代码有意义的事情。遗留代码使用图库中的URI来更改和保存图像。

在4.4之前(和谷歌驱动器),uri看起来是这样的: 内容:/ /媒体/外部/图片/媒体/ 41

正如问题中所述,它们通常是这样的: 内容:/ / com.android.providers.media.documents /文档/图片:3951

因为我需要保存图像的能力,而不打扰已经存在的代码,我只是从图库中复制URI到应用程序的数据文件夹中。然后从数据文件夹中保存的图像文件中产生一个新的URI。

这个想法是这样的:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent), CHOOSE_IMAGE_REQUEST);

public void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

    File tempFile = new File(this.getFilesDir().getAbsolutePath(), "temp_image");

    //Copy URI contents into temporary file.
    try {
        tempFile.createNewFile();
        copyAndClose(this.getContentResolver().openInputStream(data.getData()),new FileOutputStream(tempFile));
    }
    catch (IOException e) {
        //Log Error
    }

    //Now fetch the new URI
    Uri newUri = Uri.fromFile(tempFile);

    /* Use new URI object just like you used to */
 }

注意- copyAndClose()只是执行文件I/O,将InputStream复制到FileOutputStream。代码没有被发布。

这是一个完全的hack,但这是我所做的…

因此,在设置DocumentsProvider时,我注意到样例代码(在getDocIdForFile中,大约在第450行)根据文件相对于指定根的路径(即在第96行中设置mBaseDir的路径)为所选文档生成了唯一的id。

所以URI最终看起来像这样:

内容:/ / com.example.provider /文档/根:路径/ / /文件

正如文档所说,它假设只有一个根(在我的情况下是Environment.getExternalStorageDirectory(),但你可以在其他地方使用…然后它获取文件路径,从根目录开始,并使其成为唯一的ID,前置“root:”。所以我可以通过消除uri.getPath()中的“/document/root:”部分来确定路径,通过这样做来创建一个实际的文件路径:

public void onActivityResult(int requestCode, int resultCode, Intent data) {
// check resultcodes and such, then...
uri = data.getData();
if (uri.getAuthority().equals("com.example.provider"))  {
    String path = Environment.getExternalStorageDirectory(0.toString()
                 .concat("/")
                 .concat(uri.getPath().substring("/document/root:".length())));
    doSomethingWithThePath(path); }
else {
    // another provider (maybe a cloud-based service such as GDrive)
    // created this uri.  So handle it, or don't.  You can allow specific
    // local filesystem providers, filter non-filesystem path results, etc.
}

我知道。这很可耻,但它奏效了。同样,这依赖于您在应用程序中使用自己的文档提供程序来生成文档ID。

(此外,还有一种更好的方法来构建路径,不假设“/”是路径分隔符,等等。但你懂的。)

如果有人感兴趣,我为ACTION_GET_CONTENT做了一个工作的Kotlin版本:

var path: String = uri.path // uri = any content Uri
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if ("/document/image:" in path || "/document/image%3A" in path) {
    // files selected from "Documents"
    databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    selection = "_id=?"
    selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
} else { // files selected from all other sources, especially on Samsung devices
    databaseUri = uri
    selection = null
    selectionArgs = null
}
try {
    val projection = arrayOf(MediaStore.Images.Media.DATA,
        MediaStore.Images.Media._ID,
        MediaStore.Images.Media.ORIENTATION,
        MediaStore.Images.Media.DATE_TAKEN) // some example data you can query
    val cursor = context.contentResolver.query(databaseUri,
        projection, selection, selectionArgs, null)
    if (cursor.moveToFirst()) {
        // do whatever you like with the data
    }
    cursor.close()
} catch (e: Exception) {
    Log.e(TAG, e.message, e)
}

This is what I do: Uri selectedImageURI = data.getData(); imageFile = new File(getRealPathFromURI(selectedImageURI)); private String getRealPathFromURI(Uri contentURI) { Cursor cursor = getContentResolver().query(contentURI, null, null, null, null); if (cursor == null) { // Source is Dropbox or other similar local file path return contentURI.getPath(); } else { cursor.moveToFirst(); int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); return cursor.getString(idx); } } NOTE: managedQuery() method is deprecated, so I am not using it.

这个答案是来自m3n0R的问题安卓得到真正的路径Uri.getPath()和我声称没有信用。我只是想那些还没有解决这个问题的人可以使用这个。

请尽量避免使用takePersistableUriPermission方法,因为它会为我引发运行时异常。 /** 从图库中选择。 * /

public void selectFromGallery() {
    if (Build.VERSION.SDK_INT < AppConstants.KITKAT_API_VERSION) {

        Intent intent = new Intent(); 
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        ((Activity)mCalledContext).startActivityForResult(intent,AppConstants.GALLERY_INTENT_CALLED);

    } else {

        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        ((Activity)mCalledContext).startActivityForResult(intent, AppConstants.GALLERY_AFTER_KITKAT_INTENT_CALLED);
    }
}

OnActivity的结果处理图像数据:

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

    //gallery intent result handling before kit-kat version
    if(requestCode==AppConstants.GALLERY_INTENT_CALLED 
            && resultCode == RESULT_OK) {

        Uri selectedImage = data.getData();
        String[] filePathColumn = {MediaStore.Images.Media.DATA};
        Cursor cursor = getContentResolver().query(selectedImage,filePathColumn, null, null, null);
        cursor.moveToFirst();
        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String filePath = cursor.getString(columnIndex);
        cursor.close();
        photoFile = new File(filePath);
        mImgCropping.startCropImage(photoFile,AppConstants.REQUEST_IMAGE_CROP);

    }
    //gallery intent result handling after kit-kat version
    else if (requestCode == AppConstants.GALLERY_AFTER_KITKAT_INTENT_CALLED 
            && resultCode == RESULT_OK) {

        Uri selectedImage = data.getData();
        InputStream input = null;
        OutputStream output = null;

        try {
            //converting the input stream into file to crop the 
            //selected image from sd-card.
            input = getApplicationContext().getContentResolver().openInputStream(selectedImage);
            try {
                photoFile = mImgCropping.createImageFile();
            } catch (IOException e) {
                e.printStackTrace();
            }catch(Exception e) {
                e.printStackTrace();
            }
            output = new FileOutputStream(photoFile);

            int read = 0;
            byte[] bytes = new byte[1024];

            while ((read = input.read(bytes)) != -1) {
                try {
                    output.write(bytes, 0, read);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }


    }