Android中原始资源文件使用详解
来源:互联网 发布:手机照片编辑软件 编辑:程序博客网 时间:2024/05/16 23:50
转载:http://blog.csdn.net/wang_shaner/article/details/6912190
Android中原始资源文件使用详解
目录(?)[+]
背景知识介绍
与其他平台的应用程序一样,Android中的应用程序也会使用各种资源,比如图片,字串等,会把它们放入源码的相应文件夹下面,如/res/drawable, /res/xml, /res/values/, /res/raw, /res/layout和/assets。Android也支持并鼓励开发者把UI相关的布局和元素,用XML资源来实现。总结起来,Android中支持的资源有:- 颜色值 /res/values 以resources为Root的XML文件,定义形式为value
- 字串 /res/values 以resources为Root的XML文件value
- 图片 /res/drawable 直接放入,支持9 Patch可自由拉伸
- 图片的颜色 /res/values 以resources为Root的XML文件,定义形式为value
- 单位资源 /res/values 以resources为Root的XML文件value
- 菜单 /res/menu 以menuo为root的XML文件
- 布局 /res/layout 这个就是GUI的布局和元素
- 风格和主题 /res/values 以resources为Root的XML文件
- 动画 /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
;
}
}
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);
通过AssertManager来访问/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'
可以看到如果想要访问/assets下面的文件,必须要知道文件名和相对于/assets的路径。所以,如果你不预先知道其下面有什么的时候又该如何处理呢?那就需要列出它下面所有的文件,然后再选取我们需要的,所以新的问题来了,如何列出/assets下面所有的文件呢?
AssetManager提供了一个列出/assets下某个路径下面的方法:
public finalString[]list(String path)
Return a String array of all the assets at the given path.
Parameters
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().
还有一个最大的问题就是如何列出根目录/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,也就是说它是只读的。可行的办法就是读取文件然后写入一个临时文件中,再对临时文件进行想要的文件操作。可以在内部存储或外部存储上面用Contextr提供的接口来创建文件,详细的请参考这里。Java牛人可能想要用Java本身的能力:
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();
}
}
- Android中原始资源文件使用详解
- Android中原始资源文件使用详解
- Android中原始资源文件使用详解
- Android 原始资源文件的使用详解
- Android实战技巧:使用原始资源文件
- Android实战技巧:使用原始资源文件
- Android中原始资源的使用
- Android 使用原始资源
- Android 使用原始XML资源
- Android原始资源的使用
- android之使用原始资源
- android之使用原始资源
- Android 使用原始xml资源
- android中读取原始(Raw)资源
- android中读取原始(Raw)资源
- android中读取原始(Raw)资源
- 初学Android,使用原始资源(二十三)
- Android读取资源文件——读取原始Xml内容和使用Menu文件
- 【微机原理】-存储器
- Multiply Strings
- UTC时间与北京时间的差多久
- 三大数据库连接语句
- 图数据库Titan在生产环境中的使用全过程+分析
- Android中原始资源文件使用详解
- DAy8-自动完成输入内容
- Android实战技巧:深入解析AsyncTask
- Ba64 编码处理上传图片的参数失效问题
- Letter Combinations of a Phone Number
- Windows平台Mysql使表名支持大写
- js类,静态类,方法属性继承!
- 经典面试题:计算0.01+0.02+0.03+......+1.0 = ? 的值,值是50.5
- android drawable资源调用使用心得