获取存储在drawable中的图像的URI

89

我正在我的应用程序中添加一些样本项目,以便当用户第一次查看它时,它不会显得太空洞。样本项目列表应该有一个图像,我要使用的图像已经存储在应用程序的/res/drawable文件夹中。

由于我已经有一个从URI加载项目图像的方法,所以我想获取到/res/drawable/myImage.jpg的URI,但我似乎做不对。

流程如下: 创建项,其中包含表示图像URI的字符串。 将项目列表发送到List 该列表通过将字符串转换为URL并运行url.openStream()来在后台任务中加载图像。

我已经尝试了几个选项来获取URI,但没有成功。 "android.resource://....."说未知协议 "file://"文件找不到

所以现在我有点迷失如何解决这个问题..

5个回答

114

你应该使用ContentResolver来打开资源URI:

Uri uri = Uri.parse("android.resource://your.package.here/drawable/image_name");
InputStream stream = getContentResolver().openInputStream(uri);

你也可以使用这种方法打开文件和内容URI。


1
我在以下代码中遇到了MalformedUrlException异常: Uri path = Uri.parse("android.resource://se.javalia.myDrinks/drawable/image0109"); 这张图片存储在drawable文件夹中,是一个jpg文件。 - Roland
2
很奇怪,因为 Uri.parse() 不应该抛出这个异常。当您解析一个 Uri 时,它只检查是否为空引用,而不是实际解析它。 - Michael
1
我们可以同时使用这个 streamtoString() 吗? - cagcak
1
你可以将ImageView的src设置为从Michel提供的字符串解析出来的Uri。 - Eloar
你能看到我的问题吗?或者我们可以私聊一下,因为我正在尝试实现这个功能?问题链接: https://stackoverflow.com/questions/54233815/get-favicon-from-a-web-and-save-it-to-declared-icon-in-a-pojo-class - TheCoderGuy
显示剩余6条评论

59
/**
 * get uri to drawable or any other resource type if u wish 
 * @param context - context
 * @param drawableId - drawable res id
 * @return - uri 
 */
public static final Uri getUriToDrawable(@NonNull Context context, 
                                         @AnyRes int drawableId) {
    Uri imageUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE 
            + "://" + context.getResources().getResourcePackageName(drawableId)
            + '/' + context.getResources().getResourceTypeName(drawableId)
            + '/' + context.getResources().getResourceEntryName(drawableId) );
    return imageUri;
}

基于上述内容 - 适用于任何资源的微调版本:

 /**
 * get uri to any resource type Via Context Resource instance
 * @param context - context
 * @param resId - resource id
 * @throws Resources.NotFoundException if the given ID does not exist.
 * @return - Uri to resource by given id 
 */
public static final Uri getUriToResource(@NonNull Context context, 
                                         @AnyRes int resId)
                           throws Resources.NotFoundException {
    /** Return a Resources instance for your application's package. */
    Resources res = context.getResources();
    Uri resUri = getUriToResource(res,resId);
    return resUri;
}

 /**
 * get uri to any resource type via given Resource Instance
 * @param res - resources instance
 * @param resId - resource id
 * @throws Resources.NotFoundException if the given ID does not exist.
 * @return - Uri to resource by given id 
 */
public static final Uri getUriToResource(@NonNull Resources res, 
                                         @AnyRes int resId)
                           throws Resources.NotFoundException {
    /**
     * Creates a Uri which parses the given encoded URI string.
     * @param uriString an RFC 2396-compliant, encoded URI
     * @throws NullPointerException if uriString is null
     * @return Uri for this given uri string
     */
    Uri resUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
            "://" + res.getResourcePackageName(resId)
            + '/' + res.getResourceTypeName(resId)
            + '/' + res.getResourceEntryName(resId));
    /** return uri */
    return resUri;
}

一些信息:

From the Java Language spec.:

"17.5 Final Field Semantics

... when the object is seen by another thread, that thread will always
see the correctly constructed version of that object's final fields.
It will also see versions of any object or array referenced by
those final fields that are at least as up-to-date as the final fields
are."

In that same vein, all non-transient fields within Uri
implementations should be final and immutable so as to ensure true
immutability for clients even when they don't use proper concurrency
control.

For reference, from RFC 2396:

"4.3. Parsing a URI Reference

   A URI reference is typically parsed according to the four main
   components and fragment identifier in order to determine what
   components are present and whether the reference is relative or
   absolute.  The individual components are then parsed for their
   subparts and, if not opaque, to verify their validity.

   Although the BNF defines what is allowed in each component, it is
   ambiguous in terms of differentiating between an authority component
   and a path component that begins with two slash characters.  The
   greedy algorithm is used for disambiguation: the left-most matching
   rule soaks up as much of the URI reference string as it is capable of
   matching.  In other words, the authority component wins."

...

3. URI Syntactic Components

   The URI syntax is dependent upon the scheme.  
   In general, absolute URI are written as follows:

     <scheme>:<scheme-specific-part>

   An absolute URI contains the name of the scheme being used (<scheme>)
   followed by a colon (":") and then a string  (the <scheme-specific-part>) 
   whose interpretation depends on the scheme.

   The URI syntax does not require that the scheme-specific-part have any
   general structure or set of semantics which is common among all URI.
   However, a subset of URI do share a common syntax for representing
   hierarchical relationships within the namespace.  This "generic URI"
   syntax consists of a sequence of four main components:

     <scheme>://<authority><path>?<query>

来源:

争议

这个答案是正确的,但是有关final fields的部分是错误的 - 这与回答无关 - Boris Treukhov

@BorisTreukhov - 请向我们详细说明您所说的“有关final fields的部分是不正确的”是什么意思 - 问题 - 如何获得uri以构造可以解析的方式(uri如何解析?请参见答案)。

package android.net;

/**
 * Immutable URI reference. A URI reference includes a URI and a fragment, the
 * component of the URI following a '#'. Builds and parses URI references
 * which conform to
 * <a href="http://www.faqs.org/rfcs/rfc2396.html">RFC 2396</a>.
 *
 * <p>In the interest of performance, this class performs little to no
 * validation. Behavior is undefined for invalid input. This class is very
 * forgiving--in the face of invalid input, it will return garbage
 * rather than throw an exception unless otherwise specified.
 */
 public abstract class Uri implements Parcelable, Comparable<Uri> { ... }

这个答案是正确的,但是关于final字段的部分是不正确的 - 它与答案无关。 - Boris Treukhov
@ceph3us,Java语言规范中的引用(“final field semantics”)与此答案无关 - 实际的URI实现根本不使用final字段。我根本看不出其他部分有任何联系。 - Boris Treukhov
@BorisTreukhov 我们在这里讨论的是 Python 的 URI 吗?还是 C# 或 PHP 的 URI?也许我有点迷失了... - ceph3us
1
@BorisTreukhov 请注意,我们正在处理的是 Uri 而不是 URIUri 是 Android 特有的。 - Rajan Prasad
@Raymond232,非常感谢您的贡献,这对我帮助很大,现在我明白了。 - Boris Treukhov

39
你可以使用Uri.Builder代替字符串连接。
 Uri imageUri = (new Uri.Builder())
    .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
    .authority(resources.getResourcePackageName(resourceId))
    .appendPath(resources.getResourceTypeName(resourceId))
    .appendPath(resources.getResourceEntryName(resourceId))
    .build()

1
这是最佳解决方案。 - DanMan
1
完美解决方案 - Potato

33

这就是你真正需要的:

 Uri imageUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
 "://" + getResources().getResourcePackageName(R.drawable.ic_launcher)
 + '/' + getResources().getResourceTypeName(R.drawable.ic_launcher) + '/' + getResources().getResourceEntryName(R.drawable.ic_launcher) );

这需要一些权限吗?我不能使用它。 - lirui

5

in most simple form...

Uri uri = Uri.parse("android.resource://" + getPackageName() + "/" + R.drawable.book);
InputStream iStream = getContentResolver().openInputStream(uri);

“book”是drawable文件夹中文件的名称。


1
E/BitmapFactory: 无法解码流:java.io.FileNotFoundException:/2131099744(没有这样的文件或目录) - Mahmoud Mabrok

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