从Google Photos应用获取Uri路径

10

我有一个应用程序,可以使用外部应用程序选择照片。然后我从uri获取照片的路径,并将其用于内部操作。

当用户使用Google相册选择照片时,如果图片是本地存储的,则下一个代码可以完美运行。但是,如果图片在云端,则cursor.getString(index)的结果为空。

我已经搜索了一些信息,但不确定解决方案。

final String[] projection = { "_data" };
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);

if (cursor != null && cursor.moveToFirst()) {
    final int index = cursor.getColumnIndexOrThrow("_data");
    return cursor.getString(index);
}

谢谢!


看起来这是一个重复的问题? https://dev59.com/110a5IYBdhLWcg3wRWyV - Sreeram Sunkara
@user2765258 我看到了那篇帖子。但那不是一个好的解决方案。即使用户说他接受了它,因为它解决了问题,但他实施的并不是完整的解决方案。无论如何还是谢谢您。 - adalpari
2个回答

23

根据@CommonsWare的答案和之前有关此问题的帖子,我最终解决了从URI获取InputStream的问题,将其复制到新的临时文件中,并将路径传递给我需要使用的函数。

这是简化后的代码:

public String getImagePathFromInputStreamUri(Uri uri) {
    InputStream inputStream = null;
    String filePath = null;

    if (uri.getAuthority() != null) {
        try {
            inputStream = getContentResolver().openInputStream(uri); // context needed
            File photoFile = createTemporalFileFrom(inputStream);

            filePath = photoFile.getPath();

        } catch (FileNotFoundException e) {
            // log
        } catch (IOException e) {
            // log
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    return filePath;
}

private File createTemporalFileFrom(InputStream inputStream) throws IOException {
    File targetFile = null;

    if (inputStream != null) {
        int read;
        byte[] buffer = new byte[8 * 1024];

        targetFile = createTemporalFile();
        OutputStream outputStream = new FileOutputStream(targetFile);

        while ((read = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, read);
        }
        outputStream.flush();

        try {
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return targetFile;
}

private File createTemporalFile() {
    return new File(getExternalCacheDir(), "tempFile.jpg"); // context needed
}

太棒了,这帮助我摆脱了一个P0:D - silentsudo

3
当用户使用Google相册选择一张照片时,如果该图片已经存储在本地,则下一个代码可以完美地运行。但这并非必须,Uri不一定需要响应query()查询并返回_data列。它返回的值对您可能没有用处(例如,无法访问的内部存储器或可移动存储器上的文件)。如果你需要将照片加载到ImageView中,请将Uri传递给图像加载库(如Picasso)。如果你需要照片的字节,请使用ContentResolveropenInputStream()方法获取标识Uri的内容流,并在后台线程上打开和读取InputStream

谢谢,但问题在于由于内部要求,我需要真实路径。我不会展示或操作图像,只是将路径传递给已经实现的后端服务。 - adalpari
2
@adalPaRi:不存在“真实路径”。如果您需要一个文件,可以使用openInputStream()中的InputStream通过FileOutputStream对一些您控制的文件进行复制。 - CommonsWare
@CommonsWare,我在这里遇到了Google Photos的问题。我使用Picasso将URI加载到图像中,并在我的活动之间传递URI,但经过一些搜索,我发现一旦离开从Gallery/Camera ACTION_PICK意图选择器检索意图的onActivityResult,URI似乎会变得无效。你有什么建议?有任何推荐链接吗? - rgoncalv
@rgoncalv:在组件间传递Uri时,包括自己的组件,你需要使用FLAG_GRANT_READ_URI_PERMISSION。详情请参见这篇博客文章 - CommonsWare
我尝试了这个(阅读了你的博客文章):当从Activity A返回到Activity B时,在Activity A内的一个方法中,我在setResult(Activity.RESULT_OK, savedPicIntent)之前添加了picIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)。我可以在Activity B中完美地访问图片(我在Activity B中的一个小框架中看到图片,并且可以转到另一个Activity C以全屏查看图片,一切都符合预期),但是在Activity B中将图片发送到服务器(使用Firebase)时,崩溃发生在此行上:.putFile(chosenImageUri!!, metadata) - rgoncalv
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接