Android Uri获取资源文件(多种方式)

在Android中少不了去获取资源文件,在Android里封装了几种获取固定Resource文件的方式,今天不讲这个。

如果你要获取资源文件夹raw目录下的视频文件,那你会怎么做?  这时候Uri就排上用场了

 

我在这先设个疑问,通过Uri去拿raw文件夹下的mbg_unlock资源,以下哪种是正确的Uri呢?

  1. Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/mbg_unlock" );
  2. Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/" +R.raw.mbg_unlock);
  3. Uri uri = Uri.parse("android.resource://" + getPackageName() + "/" +R.raw.mbg_unlock);
  4. Uri uri = Uri.parse("android.resource://" + getPackageName() + "/xxxx/mbg_unlock" );

 

当你尝试以后你会发现,这四种都可以!是不是很神奇、很惊讶、是不是得说一句妈卖批,哈哈

读者可能会问了,前三种我还稍微可以理解,第四种也太无语了吧!别着急,我来给你解释为什么这四张都可以。

 

在Android中涉及Uri的操作一定少不了ContentResolver.java 这个类,而这个类就是我们所要找的那个关键类,如果不懂这个类是做什么的读者可以自己查一下。

通过debug在ContentResolver.java 中找到 getResourceId() 方法的这段代码,就是问题的关键。我来带大家解读一下

/**
     * Resolves an android.resource URI to a {@link Resources} and a resource id.
     *
     * @hide
     */
    public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
        String authority = uri.getAuthority();
        Resources r;
        if (TextUtils.isEmpty(authority)) {
            throw new FileNotFoundException("No authority: " + uri);
        } else {
            try {
                r = mContext.getPackageManager().getResourcesForApplication(authority);
            } catch (NameNotFoundException ex) {
                throw new FileNotFoundException("No package found for authority: " + uri);
            }
        }
        List path = uri.getPathSegments(); //对Uri包名后面根据 '/' 进行切割
        if (path == null) {
            throw new FileNotFoundException("No path: " + uri);
        }
        int len = path.size();
        int id;
        if (len == 1) {  //如果包名后面的 '/'只有一个,就直接看看是不是int型的 id ,后面代码就直接根绝这个id调用native方法进行了资源查找。这也就解释了例3可以通过。
            try {
                id = Integer.parseInt(path.get(0));
            } catch (NumberFormatException e) {
                throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
            }
        } else if (len == 2) {  //如果有两个,则调用了这个方法。下面有这个代码源码
            id = r.getIdentifier(path.get(1), path.get(0), authority);
        } else {  //如果是其他数量,则直接抛异常
            throw new FileNotFoundException("More than two path segments: " + uri);
        }
        if (id == 0) {
            throw new FileNotFoundException("No resource found for: " + uri);
        }
        OpenResourceIdResult res = new OpenResourceIdResult();
        res.r = r;
        res.id = id;
        return res;
    }
下面的是getIdentifier(path.get(1), path.get(0), authority)的源码:
int getIdentifier(String name, String defType, String defPackage) {
        if (name == null) {
            throw new NullPointerException("name is null");
        }
        try {
            return Integer.parseInt(name); //直接对包名后面的的第二个'/'后面的部分进行判断是不是int型,如果是的话直接返回,然后进行native方法取资源。这也解释了为什么例2和例4都可以通过。
        } catch (Exception e) {
            // Ignore
        }
        return mAssets.getResourceIdentifier(name, defType, defPackage); //这段代码是个native方法,系统根绝资源文件名进行查找到资源所对应的id,然后返回。这也说明了例1为什么能通过了。
    }

在上面代码里面注释部分,对上满的问题进行了一一解答。应该可以解决读者的疑惑了吧,如果还是不是很懂可以自己动手debug试试~

 

 

 

你可能感兴趣的:(Android,逻辑代码)