关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » 安卓开发 »Android Resources 资源文件的使用详解

    Android Resources 资源文件的使用详解

    2015-03-13 00:00:00 出处:投稿
    分享

    该文文章是对Android中原始资源文件的使用进行了详细的分析介绍,需要的朋友参考下。

    背景知识介绍

    与其他平台的应用程序一样,Android中的应用程序也会使用各种资源,比如图片,字串等,会把它们放入源码的相应文件夹下面,如/res/drawable, /res/xml, /res/values/, /res/raw, /res/layout和/assets。Android也支持并鼓励开发者把UI相关的布局和元素,用XML资源来实现。总结起来,Android中支持的资源有:

    颜色值 /res/values 以resources为Root的XML文件,定义形式为<color name>value</color> 字串 /res/values 以resources为Root的XML文件<string name>value</string> 图片 /res/drawable 直接放入,支持9 Patch可自由拉伸 图片的颜色 /res/values 以resources为Root的XML文件,定义形式为<drawable name>value</drawable> 单位资源 /res/values 以resources为Root的XML文件<dimen name>value</dimen> 菜单 /res/menu 以menuo为root的XML文件 布局 /res/layout 这个就是GUI的布局和元素 风格和主题 /res/values 以resources为Root的XML文件<style name>value</style> 动画 /res/anim 有二种:一个是帧动画(frame animation),也就是连续变换图片以animation-list为Root的XML文件;另外一种就是补间动画(tweened animation),它对应于API中的Animation和AnimationSet,有translate、scale、rotate、alpha四种,以set为root来定义,这个set就相当于AnimationSet

    再说下目录:

    /res/anim 用于存放动画 /res/drawable 存放图片,或等同于图片的资源如shape,或selector /res/menu 存放Menu /res/values 存放修饰性资源:字串,颜色,单位,风格和主题 /res/layout 存放UI布局和元素 /res/raw 存放运行时想使用的原始文件 /assets 存放运行时想使用的原始文件

    除了原始文件目录/res/raw和/assets以外,其他的资源在编译的时候都会被第三方软件aapt进行处理,一个是把图片和XML文件进行处理,例如把XML编译成为二进制形式;另外处理的目的就是生成R.java文件,这个文件是访问资源时必须要用到的。

    /res目录下面的所有文件都会映射到R.java文件中,以整数Id的形式被标识,相同类型的资源被一个内部类来封装,一个R.java的文件类似于这样:

    /* AUTO-GENERATED FILE.  DO NOT MODIFY.
     *
     * This class was automatically generated by the
     * aapt tool from the resource data it found.  It
     * should not be modified by hand.
     */
    package com.android.explorer;
    public final class R {
        public static final class attr {
        }
        public static final class drawable {
            public static final int icon=0x7f020000;
        }
        public static final class id {
            public static final int action=0x7f060004;
            public static final int description_panel=0x7f060001;
            public static final int fileinfo=0x7f060003;
            public static final int filename=0x7f060002;
            public static final int linearlayout_test_1=0x7f060005;
            public static final int linearlayout_test_2=0x7f060006;
            public static final int linearlayout_test_3=0x7f060007;
            public static final int thumbnail=0x7f060000;
        }
        public static final class layout {
            public static final int fileant_list_item=0x7f030000;
            public static final int linearlayout_test=0x7f030001;
        }
        public static final class raw {
            public static final int androidmanifest=0x7f040000;
        }
        public static final class string {
            public static final int app_name=0x7f050001;
            public static final int hello=0x7f050000;
        }
    }

    从这个R.java就可看出在/res中定义或提供资源时的注意事项:

    1. 同一个类型,或同一文件夹下面的资源不可以使用相同的文件名,也就是说不能用文件扩展名来区别不同的文件,因为R.java中只保留资源的文件名而不管扩展名,所以假如有二个图片一个是icon.png另一个是icon.jpg,那么在R.java中只会有一个R.drawable.icon。另外一个则会无法访问到。

    2. 资源文件的名字必须符合Java变量的命名规则,且不能有大写,只能是’[a-z][0-9]._’,否则会有编译错误,因为R.java中的变量Id要与资源中的文件一一对应,也就是说用资源文件名来作为Id的变量名,所以一定要符合Java变量的命名规则,另外它还不能有大写。

    3. 除了SDK支持的folder外,不能再有子Folder,虽不会有编译错误,但是子Folder会被完全忽略,如在/res/layout下在建一个子Folder activity(/res/layout/acitivity/, 那么你在生成的R.java中是看不到activity和其内的内容的。

    4. 对于资源文件的大小有限制,最好不要让单个文件大于1M,这是SDK文档说明的限制,但具体的我没有进行试验(据说2.2版本以后的可支持到10M,不知道是真的还是假的)

    5. 所有/res下面的资源都能通过Resources()并提供Id来访问。

    使用原始资源

    对于大多数资源在编译时会对文件内容进行特殊处理,以方便Apk在运行时访问。 假如想要运行时使用未经处理的原始资源,可以把资源文件放在/res/raw和/assets目录下面,这二个目录的主要区别在于:

    1. /res/raw中的文件会被映射到R.java中

    虽然/res/raw中的文件不会被aapt处理成为二进制,但是它的文件还是被映射到R.java中,以方便以资源Id形式来访问

    2. 子目录结构

    如上面所述,/res/raw中虽可以有子目录,但是在程序运行时是无法访问到的,因为/res下面的所有非法子目录在R.java中都是看不到的。而且这些子目录和文件都不会被编译进入Apk中,解压Apk文件后也看不到/res/raw下面去找了。
    而/assets是允许有子目录的,并且完全可以访问到,并且会被打包进Apk,解压Apk后,这些文件仍然存在并且与源码包中的一样。

    3. 访问方式

    /res/raw下面的文件(子文件夹是访问不到的了)的访问方式是通过Resources,并且必须提供资源的Id

    InputStream in = Context.getResources().openRawResource(R.id.filename);

    所以为什么子文件夹无法访问,因为没有Id啊。

    而/assets则要通过AssetManager来访问。下面着重讲解如何访问/assets下面的资源文件。

    通过AssetManager来访问/assets下面的原始资源文件

    1. 文件的读取方式

    用AssetManager.open(String filename)来打开一个文件,这是一组重载方法,还有其他参数可以设置打开模式等,可以参考文档
    这里的filename是相对于/assets的路径,比如:

    InputStream in = mAssetManager.open("hello.txt"); // '/assets/hello.txt'
    InputStream in2 = mAssetManager.open("config/ui.txt"); // '/assets/config/ui.txt'

    2. 文件夹处理 — 如何遍历/assets

    可以看到假如想要访问/assets下面的文件,必须要知道文件名和相对于/assets的路径。所以,假如你不预先知道其下面有什么的时候又该如何处理呢?那就需要列出它下面所有的文件,然后再选取我们需要的,所以新的问题来了,如何列出/assets下面所有的文件呢?
    AssetManager提供了一个列出/assets下某个路径下面的方法:

    public finalString[]list(String path)
    Since: API Level 1
    Return a String array of all the assets at the given path.
    Parameters
    path  A relative path within the assets, i.e., "docs/home.html". 
    Returns
     String[] Array of strings, one for each asset. These file names are relative to 'path'. You can open the file by concatenating 'path' and a name in the returned string (via File) and passing that to open().

    其实这个文档写的有问题,list()是列出一个文件夹下面的文件,所以应该传入一个文件夹路径而非文档中的”docs/home.html”。

    还有一个最大的问题就是如何列出根目录/assets下面的内容,因为只有知道了根目录下面的东西,才能去相对的子目录去找东西,所以这是个必须最先解决的问题。

    其实文档没有说的太明白这个方法到底如何使用,也就是说这个String参数到底如何传。猜想着根目录为/assets,所以尝试了以下:

    mAssetManager.list(".");  // returns array size is 0
    mAssetManager.list("/");  // returns [AndroidManifest.xml, META-INF, assets, classes.dex, res, resources.arsc] // don't worry, u can see these files though, no way to access them
    mAssetManager.list("/assets");  // returns array size is 0
    //Google了一下,找到了正解:
    mAssetManager.list("");  // returns stuff in /assets

    然后再根据所列出的子项去递归遍历子文件,直到找到所有的文件为止。

    常见的问题

    1. 资源文件只能以InputStream方式来获取

    假如想操作文件怎么办,假如想要用文件Uri怎么办。光靠API当然不行,它只给你InputStream,也就是说它是只读的。可行的办法就是读取文件然后写入一个临时文件中,再对临时文件进行想要的文件操作。可以在内部存储或外部存储上面用Context提供的接口来创建文件。

    File File.createTempFile(String prefix, String suffix);  
    File File.createTempFile(String prefix, String suffix, File path);

    这也是可以的,但要考虑Android系统的特性,也就是说所写的路径是否有权限。比如对于第一个方法,用的是”java.io.tmpdir”这个在Android当中就是”/sdcard”,所以当没有SD卡时这个方法必抛异常。

    2. 所有资源文件都是只读的,运行时无法更改

    因为,程序运行时是把Apk动态解析加载到内存中,也就是说,Apk是不会有变化的,它是无法被改变的。

    3. 所有的资源文件夹/res和/assets也都是只读的,不可写入

    如上面所说,Apk是在编译后是无法再改变的了。

    实例

    下面是一个实例,可以递归式的遍历/assets下面所有的文件夹和文件

    package com.android.explorer;
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import android.app.ListActivity;
    import android.content.Context;
    import android.content.Intent;
    import android.content.res.AssetManager;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Environment;
    import android.text.TextUtils;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.webkit.MimeTypeMap;
    import android.widget.BaseAdapter;
    import android.widget.ImageButton;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    /*
     * Explore all stuff in /assets and perform actions specified by users.
     */
    public class FileAntActivity extends ListActivity {
        private static final String TAG = "FileAntActivity";
        private AssetManager mAssetManager;
        private static final String EXTRA_CURRENT_DIRECTORY = "current_directory";
        private static final String EXTRA_PARENT = "parent_directory";
        public static final String FILEANT_VIEW = "com.android.fileant.VIEW";
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Intent intent = getIntent();
            String current = null;
            String parent = null;
            if (intent != null && intent.hasExtra(EXTRA_CURRENT_DIRECTORY)) {
                current = intent.getStringExtra(EXTRA_CURRENT_DIRECTORY);
            }
            if (current == null) {
                current = "";
            }
            if (intent != null && intent.hasExtra(EXTRA_PARENT)) {
                parent = intent.getStringExtra(EXTRA_PARENT);
            }
            if (parent == null) {
                parent = "";
            }
            mAssetManager = getAssets();
            if (TextUtils.isEmpty(parent)) {
                setTitle("/assets");
            } else {
                setTitle(parent);
            }
            try {
                // List all the stuff in /assets
                if (!TextUtils.isEmpty(parent)) {
                    current = parent + File.separator + current;
                }
                Log.e(TAG, "current: '" + current + "'");
                String[] stuff = mAssetManager.list(current);
                setListAdapter(new FileAntAdapter(this, stuff, current));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private class FileAntAdapter extends BaseAdapter {
            private Context mContext;
            private String[] mEntries;
            private String mParentDirectory;
    
            public FileAntAdapter(Context context, String[] data, String parent) {
                mContext = context;
                this.mEntries = data;
                mParentDirectory = parent;
            }
    
            public int getCount() {
                return mEntries.length;
            }
            public Object getItem(int position) {
                return mEntries[position];
            }
            public long getItemId(int position) {
                return (long) position;
            }
            public View getView(final int position, View item, ViewGroup parent) {
                LayoutInflater factory = LayoutInflater.from(mContext);
                if (item == null) {
                    item = factory.inflate(R.layout.fileant_list_item, null);
                    TextView filename = (TextView) item.findViewById(R.id.filename);
                    TextView fileinfo = (TextView) item.findViewById(R.id.fileinfo);
                    ImageButton action = (ImageButton) item.findViewById(R.id.action);
                    final String entry = mEntries[position];
                    filename.setText(entry);
                    boolean isDir = isDirectory(entry);
                    if (isDir) {
                        fileinfo.setText("Click to view folder");
                        action.setVisibility(View.GONE);
                        item.setClickable(true);
                        item.setOnClickListener(new View.OnClickListener() {
                            public void onClick(View view) {
                                Intent intent = new Intent(FILEANT_VIEW);
                                intent.putExtra(EXTRA_CURRENT_DIRECTORY, entry);
                                intent.putExtra(EXTRA_PARENT, mParentDirectory);
                                startActivity(intent);
                            }
                        });
                    } else {
                        final String type = 
                            MimeTypeMap.getSingleton().getMimeTypeFromExtension(getExtension(entry));
                        fileinfo.setText(type);
                        item.setClickable(false);
                        action.setOnClickListener(new View.OnClickListener() {
                            public void onClick(View view) {
                                 String filepath = entry;
                                 if (!TextUtils.isEmpty(mParentDirectory)) {
                                     filepath = mParentDirectory + File.separator + filepath;
                                 }
                                 BufferedInputStream in = new BufferedInputStream(mManager.open(filepath));
                                 // Do whatever you like with this input stream
                            }
                        });
                    }
                }
                return item;
            }
         }
    
        /**
         * Test Whether an entry is a file or directory based on the rule:
         * File: has extension *.*, or starts with ".", which is a hidden files in Unix/Linux,
         * otherwise, it is a directory
         * @param filename
         * @return
         */
        private boolean isDirectory(String filename) {
            return !(filename.startsWith(".") || (filename.lastIndexOf(".") != -1));
        }
    
        private String getExtension(String filename) {
            int index = filename.lastIndexOf(".");
            if (index == -1) {
                return "";
            }
            return filename.substring(index + 1, filename.length()).toLowerCase();
        }
    }
    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    帝国CMS7.5编辑器上传图片取消宽高的三种方法

    帝国cms如何自动生成缩略图的实现方法

    Windows 12即将到来,将彻底改变人机交互

    帝国CMS 7.5忘记登陆账号密码怎么办?可以phpmyadmin中重置管理员密码

    帝国CMS 7.5 后台编辑器换行,修改回车键br换行为p标签

    Windows 11 版本与 Windows 10比较,新功能一览

    Windows 11激活产品密钥收集及专业版激活方法

    如何从 Windows 11 中完全删除/卸载 OneNote?无解!

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    IT头条

    华为Pura80系列新机预热,余承东力赞其复杂光线下的视频拍摄实力

    01:28

    阿里千问3开源首战告捷:全球下载破千万,国产AI模型崛起新高度!

    01:22

    DeepSeek R1小版本试升级:网友实测编程能力已达到国际一线水平

    23:15

    NVIDIA 与 Dell 合作,大规模交付 Blackwell AI 系统

    20:52

    Cerebras 以最快的 Llama 4 Maverick 性能引领 LLM 推理竞赛

    20:51

    技术热点

    PHP中的随机性——你觉得自己幸运吗?

    搞定Ubuntu Linux下WPA无线上网

    Java使用内存映射实现大文件的上传

    MySQL安全性指南

    MySQL两项性能的基本测试浅谈

    教您使用UniqueIdentifier选取SQL Server主键

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。