Android(3)——App Resources


原文地址:App Resources


它不仅仅是一个好的app的一段代码,Resources是一个额外的文件,它是静态写在程序中的,例如bitmaps、layout definitions、user interface strings、animation instructions等等。


一、Resources Overview 概览

通常我们应该将程序中的图片或者string从代码中提取出来然后写在Resources中,因为这样有助于我们管理这些资源,也有助于app支持各种不同的语言、屏幕大小,可以支持各种各样的配置。

那为了实现这个功能,通常我们将这些Resources都组织值res/的文件夹下,然后再根据这个下面的一些文件夹进行设置区分。

对于任意的Resources你都可以为它设定默认值或者是多选项:

Default Resources(默认值):不在乎设备配置,或者当没有可选项的时候用它。

Alternative Resources(多选项):根据不同的设备配置自动获取某项。你要通过文件名来对不同的选项设置不同的匹配项。

举例:


如果只有一个默认选项,那就只能像上面的这个图了。


那如果你有多种选项来适配不同的设备时,效果就是酱紫,哈。



点击打开链接

二、Providing Resources 资源类型

这里讲一下Resources提供了哪些资源类型。我们应该将不同类型的Resources放在res/下的不同目录中。就像这样:

MyProject/
    src/  
        MyActivity.java  
    res/
        drawable/  
            icon.png  
        layout/  
            main.xml
            info.xml
        values/  
            strings.xml 
下面的Table1展示了在res/目录下支持的目录名称:



注意点一:不要直接将资源文件 resource files直接放到res/文件夹下,会造成编译错误。

上表中定义的子文件夹都属于默认值Default。但是不同的设备要用不同类型的资源。所以你还是要弄多选项的。

那关于多选项的名称的创建规则是这样的:

<resources_name>-<config_qualifier>

<resources_name>是默认资源的名称,它们是定义在上面Table1中的那些文件夹。

<qualifier>是用来区分不同选项的特殊的参数,它定义在下面的Table2中,可以参考一下。可以同时跟多个破折号,也就是多个<qualifier>。

注意点二:当跟多个<qualifier>的时候,注意它们的顺序要跟Table2中出现的顺序相同才行。

举例:

res/
    drawable/   
        icon.png
        background.png    
    drawable-hdpi/  
        icon.png
        background.png

下面Table2给出了可用的限定符:

MCC and MNC:手机国家地区编码

Language and region:语言和地区


Layout Direction:布局方向?


smallestWidth:屏幕大小



Available width:最小可接受的屏幕宽度


Available height:最小可接受的屏幕高度


Screen size:屏幕大小


Screen aspect:屏幕长短

Screen orientation:屏幕方向


UI mode:UI模式

Night mode:夜间模式


Screen pixel density(dpi):屏幕分辨率


Touchscreen type:触屏类型


Keyboard available:键盘是否可用


Primary text input method:初始输入

Navigation key available:导航

Primary nontouch navigation method:导航


Platform Version(API level):平台版本



限定符使用规则:

1、按Table2中的顺序使用多个限定符:

 drawable-en-rUS-land applies to US-English devices in landscape orientation.

2、按顺序!

3、不可以相互嵌套,例如:res/drawable/drawable-en/

4、不区分大小写的。

5、如果统一资源属于两个限定符中,那就把这个资源复制到两个文件夹下。同一类型的限定符不可以同时使用,例如:drawable-rES-rFR/,但是!你也没有必要把资源复制两份,你可以使用alias resources!


所有的匹配都是Android自动进行的。


创建alias resources:

注意点一:并不是所有的resources都适用于这个功能,例如:animation、menu、raw、unspecified resources in xml/。

先举例吧:

Drawable

To create an alias to an existing drawable, use the <bitmap> element. For example:

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/icon_ca" />
假设我们有一个图片icon.png,还需要放在   res/drawable-en-rCA/  and res/drawable-fr-rCA/。然后我们可以把它的名字保存成例如icon_ca.png,放在默认的res/drawable/文件下。然后再创建一个icon.xml文件分别放在res/drawable-en-rCA/ and res/drawable-fr-rCA/中,这个icon.xml中通过bitmap的src属性引用了icon_ca.png,这样你就可以直接通过icon.xml来使用啦。这样当我们引用的时候要写R.drawable.icon!!!!


再举一个例子:

Layout

To create an alias to an existing layout, use the <include> element, wrapped in a <merge>. For example:

<?xml version="1.0" encoding="utf-8"?>
<merge>
    <include layout="@layout/main_ltr"/>
</merge>
如果我们把上面的文件存为main.xml,那么使用的时候就写R.layout.main。


再举个例子:

Strings and other simple values

To create an alias to an existing string, simply use the resource ID of the desired string as the value for the new string. For example:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello</string>
    <string name="hi">@string/hello</string>
</resources>
这样就可以用R.string.hi来代替R.string.hello。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="yellow">#f00</color>
    <color name="highlight">@color/red</color>
</resources>

Android系统要根据资源来得到最佳匹配:

注意点一:如果你的应用适应多种限定,那你一定要提供一个默认资源保证应用正确运行。否则可能没有了

注意点二:如果你的应用适应横屏和竖屏,不要这样写: layout-land/ for landscape andlayout-port/ for portrait。而要这样写:layout/ for landscape and layout-port/ for portrait。

注意点三:默认选项还有一个重要意义就是版本升级后你可能没有新的限定资源。

有一个例外:当你的minSdkVersion是4以上的时候,你不需要默认的drawable resources来面对不同分辨率限定符。Android会自动去匹配最佳的。不过为了显示效果,你还是提供不同分辨率的图片好了。


Android是如何寻找最佳匹配资源的呢?

按照Table2中的限定符,一个一个的对比。在匹配过程中,分辨率是最后才考虑的。正如在Table2中它放在最后。


在屏幕大小screen size限定中,当没有直接匹配时,系统会选择一个比当前屏幕更小的屏幕。当如果只有更大的屏幕时,系统不会采用它,你的应用将会崩溃。



Accessing Resources

三、Accessing Resources 访问资源

应用程序编译后,aapt会自动生成R.java,它里面包含所有的资源ID。

由resource type(string、drawable、layout)和resource name组成。

访问方法:

1、在代码中这样写:R.string.hello。

2、在XML文件中这样写:@string/hello


具体介绍在代码中访问资源:

这样直接使用:

ImageView imageView = (ImageView) findViewById(R.id.myimageview);
imageView.setImageResource(R.drawable.myimage);
或者是通过Resources中的方法来检索,通过Context.getResources()。


语法Syntax:

[<package_name>.]R.<resource_type>.<resource_name>
<package_name>是你的资源所在的包名,如果在同一个包下,就不用写了。

<resource_type>资源类型

<resource_name>资源名称


举例吧:

// Load a background for the current screen from a drawable resource
getWindow().setBackgroundDrawableResource(R.drawable.my_background_image) ;

// Set the Activity title by getting a string from the Resources object, because
//  this method requires a CharSequence rather than a resource ID
getWindow().setTitle(getResources().getText(R.string.main_title));

// Load a custom layout for the current screen
setContentView(R.layout.main_screen);

// Set a slide in animation by getting an Animation from the Resources object
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
        R.anim.hyperspace_in));

// Set the text on a TextView object using a resource ID
TextView msgTextView = (TextView) findViewById(R.id.msg);
msgTextView.setText(R.string.hello_message);
注意点一:永远不要去修改R.java文件。


具体介绍在XML中访问资源:

<Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/submit" />
语法Syntax:

@[<package_name>:]<resource_type>/<resource_name>
举例吧:

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <color name="opaque_red">#f00</color>
   <string name="hello">Hello!</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
    android:layo
18db
ut_width="fill_parent"
    android:layout_height="fill_parent"
    android:textColor="@color/opaque_red"
    android:text="@string/hello" />
如果引用的是系统资源,那就需要加上包名:

<?xml version="1.0" encoding="utf-8"?>
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:textColor="@android:color/secondary_text_dark"
    android:text="@string/hello" />
注意点一:应该使用string资源,这样你的应用程序就可以适应于各种语言。


学会用alias resources:

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/other_drawable" />


引用style attributes样式属性:

style attribute资源就是当前应用的主题里的属性。通过引用style attribute可以帮助我们使用自定义的属性。主要强调的是:自定义!!!当前主题!!!

语法Syntax:把@换成?

?[<package_name>:][<resource_type>/]<resource_name>
举例:

<EditText id="text"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textColor="?android:textColorSecondary"
    android:text="@string/hello_world" />
Here, the  android:textColor  attribute specifies the name of a style attribute in the current theme. Android now uses the value applied to the  android:textColorSecondary  style attribute as the value for  android:textColor  in this widget. Because the system resource tool knows that an attribute resource is expected in this context, you do not need to explicitly state the type (which would be  ?android:attr/textColorSecondary )—you can exclude the attr  type.


引用平台资源Platform Resources:

Android包含了很多标准资源,例如styles、themes and layouts。为了引用这些资源,确保你你的资源引用了android package name。

setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myarray));
  simple_list_item_1  就是定义子啊ListView中的一个layout resource。


四、Handing Runtime Changes 随运行时间改变处理

当设备参数(screen orientation、keyboard availability、language、接电话)在运行时发生变化时,Android就会重启activity(先onDestroy(),然后onCreate()),然后选择相对应的可选资源。

因为了重启activity,因此保存上一次的运行状态很重要。Android是通过在destroys前调用onSaveInstanceState()在保存程序状态,然后在重启时调用onCreate()或者onRestoreInstanceState()。

因为保存重启会带来较差的用户体验,我们可以使用下面的这两种方式:

1、在配置发生变化的时候保存一个对象。

让系统去重启activity。

2、你自己来处理配置变化。

当配置变化时组织系统重启你的activity,而是根据需求回调来手动的更新你的activity。


具体介绍:在配置发生变化的时候保存一个对象

重启一个活动需要恢复各种数据,比如说网络连接、密集操作,带来差的用户体验。而且也可能不能够完全重建。系统会通过回调onSaveInstanceState(),它里面有用Bundle,但是它不适合于存储大量的数据内容,而且bundle存储的数据必须要序列化。当然系统也可以使用另一种方式那就是使用Fragment碎片。

当Android系统由于配置变化要关闭你的activity时,你的activity中标记了去保存数据的fragments却不会被销毁。你可以给你的activity添加这样的Fragment来保存数据对象。

方法呢就是:

  1. Extend the Fragment class and declare references to your stateful objects.
  2. Call setRetainInstance(boolean) when the fragment is created.
  3. Add the fragment to your activity.
  4. Use FragmentManager to retrieve the fragment when the activity is restarted.
举例吧:

public class RetainedFragment extends Fragment {

    // data object we want to retain
    private MyDataObject data;

    // this method is only called once for this fragment
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // retain this fragment
        setRetainInstance(true);
    }

    public void setData(MyDataObject data) {
        this.data = data;
    }

    public MyDataObject getData() {
        return data;
    }
}
注意点一:当你想要保存任意对象的时候,确保这个对象和Activity无关联,例如a Drawable、an Adapter、a View 或其他任何和Context有关联的对象。不然就会泄漏所有之前的view和resource。这里泄漏的含义是说它们无法被回收,浪费内存。

然后通过Fragmentmanager将这个fragment添加到Activity中。

public class MyActivity extends Activity {

    private RetainedFragment dataFragment;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // find the retained fragment on activity restarts
        FragmentManager fm = getFragmentManager();
        dataFragment = (DataFragment) fm.findFragmentByTag(“data”);

        // create the fragment and data the first time
        if (dataFragment == null) {
            // add the fragment
            dataFragment = new DataFragment();
            fm.beginTransaction().add(dataFragment, data”).commit();
            // load the data from the web
            dataFragment.setData(loadMyData());
        }

        // the data is available in dataFragment.getData()
        ...
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // store the data in the fragment
        dataFragment.setData(collectMyLoadedData());
    }
}


具体介绍:你自己来处理配置变化

如果你的应用在特定配置变化情况下不需要更新资源那么手动的组织活动重启,然后自己来处理。

注意点一:手动处理是比较麻烦的,因为系统不会自动的为你执行手动处理。这个技术需要你去做一系列的操作,并且在很多的应用中并不建议用手动处理。

那为了声明你要手动处理,你需要去修改Manifest文件中的<activity>元素,让它包含android:configChanges这个属性。这是属性可选的值有:



最常用的值呢就是"orientation","keyboardHidden"。可以同时声明多个用 | 来分割。有一个满足条件就不重启。然后会调用onConfigurationChanged(),在这个函数中你可以根据配置的变化手动更新你activity中的资源。

 This method is passed a Configuration object that specifies the new device configuratio 1ac5 n. By reading fields in the Configuration, you can determine the new configuration and make appropriate changes by updating the resources used in your interface. 

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">
注意点二:当你的API level在13以上时,要在config中加入“screenSize”这个值,但如果是12以下的话,就随便啦。

下面这个例子实现了检测当前设备的orientation:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}
这个Configuration object代表了所有当前的配置,不仅仅是改变了的那些配置。大多数的时候你不需要精确的知道所有改变的配置,仅仅需要简单的手动去设置那些由于某些配置改变而引起的资源的改变。

比如说,因为Resources对象被更新,你可以通过setImageResource()重设所有的ImageViews。

注意点三:来自Configuration的值都是整数,在Configuration类中匹配特定的常数。具体的对应值去查啦。

注意四点:当你手动处理配置变化时,你必须要重设所有你提供了的可选项。

当配置变化时,如果你不需要修改任何资源,那你可以不用去实现onConfigurationChanged()。这里你就仅仅是阻止了活动的重启。但是最好还是不要这样用啦,还是安心重启好了



Localizing with Resources

五、Localizing with Resources 本地化资源

没看懂啊



六、Resource Types

博客链接:Animation












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值