插件化框架设计(二) Android 资源加载机制详解(一)

本文涉及的产品
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Android 提供了一种非常灵活的资源系统,可以根据不同的条件提供可替代资源。因此,系统基于很少的改造就能支持新特性,比如 Android N 中的分屏模式。这也是 Android 强大部分之一。本文主要讲述 Android 资源系统的实现原理,以及在应用开发中需要注意的事项。

一、定义资源

Android 使用 XML 文件描述各种资源,包括字符串、颜色、尺寸、主题、布局、甚至是图片(selector,layer-list)。资源可分为两部分,一部分是属性,另一部分是值。对于 android:text="hello world",text 就是属性,hello,world 就是值

1. 属性的定义

在 APK 程序中,属性定义在 res/values/attrs.xml 中,在系统中属性位于
framework/base/core/res/res/values/attrs.xml 文件中。具体定义如下所示:

<declare-styleable name="Window"> 
<attr name="windowBackground" format="reference"/> 
<attr name="windowContentOverlaly" /> 
<attr name="windowFrame" /> 
<attr name="windowTitle" />
</declare-styleable>

styleable 相当于一个属性集合,其在 R.java 文件中对应一个 int[]数组,aapt 为styleable 中的每个 attr(属性)分配一个 id 值,int[]中的每个 id 对应着 styleable中的每一个 attr。

对于,Window 相当于属性集合的名称。
对于,windowBackground 相当于属性的名称;属性名称在应用程序范围内必须唯一,既无论定义几个资源文件,无论定义几个styleable,windowBackground 必须唯一。

在 Java 代码中,变量在一个作用域内只能声明一次,但可以多次使用。attr 也是一样,只能声明一次,但可以多处引用。如上代码所示,在 Window 中声明了一个名为 windowBackground 的 attr,在 Window 中引用了一个名为windowTitle 的 attr。

如果一个 attr后面仅仅有一个 name,那么这就是引用;如果不光有 name 还有 format那就是声明。windowBackground 是属性的声明,其不能在其他 styleable 中再次声明;windowTitle 则是属性的引用,其声明是在别的 styleable 中。

2. 值的定义

常见的值一般有以下几种:

  • String,Color,boolean,int 类型:在 res/values/xxx.xml 文件中指定
  • Drawable 类型:在 res/drawable/xxx 中指定
  • layout(布局):在 res/layout/xxx.xml 中指定
  • style(样式):在 res/values/xxx.xml 中指

值的类型大致分为两类,一类是基本类型,一类是引用类型;对于 int,boolean等类型在声明属性时使用如下方式:

<attr name="width" format="integer"/>
<attr name="text" format="string" />
<attr name="centerInParent"="boolean"/>

对于 Drawable,layout 等类型在声明属性时:

<attr name="background" format="reference"/>

二、解析资源

资源解析主要涉及到两个类,一个是 AttributeSet,另一个是 TypedArray。

1. AttributeSet

该类位于 android.util.AttributeSet,纯粹是一个辅助类,当从 XML 文件解析时会返回 AttributeSet 对象,该对象包含了解析元素的所有属性及属性值。并且在解析的属性名称与 attrs.xml 中定义的属性名称之间建立联系。
AttributeSet 还提供了一组 API 接口从而可以方便的根据 attrs.xml 中已有的名称获取相应的值。

如果使用一般的 XML 解析工具,则可以通过类似 getElementById()等方法获取属性的名称和属性值,然而这样并没有在获取的属性名称与 attrs.xml 定义的属性名称之间建立联系。

Attribute 对象一般作为 View 的构造函数的参数传递过来,例如:

publlic TextView(Context context,AttributeSet attrs,int defStyle)

AttributeSet 中的 API 可按功能分为以下几类,假定 TextView 定义如下所示:

<TextView
android:id="@+id/tv"
android:layout_width="@dimen/width"
android:layout_height="wrap_content"
style="@stylel/text"/>

第一类,操作特定属性:

public String getIdAttribute()

获 取 id 属 性 对应 的 字 符 串 ,此 处 返回”@+id/tv”

public String getStyleAttribute()

获 取 style 属性 对应 的字 符串, 返回”@style/text”

public int getIdAttributeResourceValue(int defaultValue)

返回 id 属性对应的 int 值,此处对应 R.id.tv

第二类,操作通用属性

public int getAttributeCount()

获取属性的数目,本例中返回 4

public String getAttributeName(int index)

根据属性所在位置返回相应的属性名称。例如,id=0,layout_width=1,layout_height=2,style=3,如果

getAttributeName(2)

则返回 android:layout_height 

public String getAttributeValue(int index)

根据位置返回值。本例中,

getAttributeValue(2)

则返回”wrap_content”。

public String getAttributeValue(String namespace,String name)

返回指定命名空间,指定名称的属性值,该方法说明 AttributeSet 允许给一个 XMLElement 的属性增加多个命名空间的属性值。

public int getAttributeResource(int index)

返回指定位置的属性 id 值。本例中,getAttributeResource(2)返回 R.attr.layout_width。前面也说过,系统会为每一个 attr 分配一个唯一的 id。

第三类,获取特定类型的值:

public XXXType getAttributeXXXType(int index,XXXType defaultValue)

其 中XXXType 包括 int、unsigned int、boolean、float 类型。使用该方法时,必须明确知道某个位置(index)对应的数据类型,否则会返回错误。而且该方法仅适用于特定的类型,如果某个属性值为一个 style 类型,或者为一个 layout类型,那么返回值都将无效。

2. TypedArray

程序员在开发应用程序时,在 XML 文件中引用某个变量通常是android:background=”@drawable/background”,该引用对应的元素一般为某个View/ViewGroup,而 View/ViewGroup 的构造函数中会通过obatinStyledAttributes 方法返回一个 TypedArray 对象,然后再调用对象中的getDrawable()方法获取背景图片。

TypedArray 是对 AttributeSet 数据类的某种抽象。对于andorid:layout_width="@dimen/width",如果使用 AttributeSet 的方法,仅仅能获取”@dimen/width”字符串。而实际上该字符串对应了一个 dimen 类型的数据。

TypedArray 可以将某个 AttributeSet 作为参数构造 TypedArray 对象,并提供更方便的方法直接获取该 dimen 的值

TypedArray a = context.obtainStyledAttributes(attrs,com.android.internal.
R.styleable.XXX,defStyle,0)

方法 obtainStyledAttributes()的第一个参数是一个 AttributeSet 对象,它包含了一个 XML 元素中定义的所有属性。第二个参数是前面定义的 styleable,appt 会把一个 styleable 编译成一个 int[]数组,该数组的内部实现正是通过遍历AttributeSet 中的每一个属性,找到用户感兴趣的属性,然后把值和属性经过重定位,返回一个 TypedArray 对象。想要获取某个属性的值则调用相关的方法即可,比如 TypedArray.getDrawbale(),TypedArray.getString()等。getDrawable(),getString()方法内部均通过 Resources 获取属性值。

相关文章
|
2月前
|
SQL 缓存 安全
Android ORM 框架之 greenDAO
Android ORM 框架之 greenDAO
66 0
|
2月前
|
Android开发
Android 插件化
Android 插件化
24 0
|
13天前
|
安全 JavaScript 前端开发
kotlin开发安卓app,JetPack Compose框架,给webview新增一个按钮,点击刷新网页
在Kotlin中开发Android应用,使用Jetpack Compose框架时,可以通过添加一个按钮到TopAppBar来实现WebView页面的刷新功能。按钮位于右上角,点击后调用`webViewState?.reload()`来刷新网页内容。以下是代码摘要:
|
14天前
|
JavaScript Java Android开发
kotlin安卓在Jetpack Compose 框架下跨组件通讯EventBus
**EventBus** 是一个Android事件总线库,简化组件间通信。要使用它,首先在Gradle中添加依赖`implementation &#39;org.greenrobot:eventbus:3.3.1&#39;`。然后,可选地定义事件类如`MessageEvent`。在活动或Fragment的`onCreate`中注册订阅者,在`onDestroy`中反注册。通过`@Subscribe`注解方法处理事件,如`onMessageEvent`。发送事件使用`EventBus.getDefault().post()`。
|
14天前
|
JavaScript 前端开发 Android开发
kotlin安卓在Jetpack Compose 框架下使用webview , 网页中的JavaScript代码如何与native交互
在Jetpack Compose中使用Kotlin创建Webview组件,设置JavaScript交互:`@Composable`函数`ComposableWebView`加载网页并启用JavaScript。通过`addJavascriptInterface`添加`WebAppInterface`类,允许JavaScript调用Android方法如播放音频。当页面加载完成时,执行`onWebViewReady`回调。
|
18天前
|
缓存 Android开发 Kotlin
【安卓app开发】kotlin Jetpack Compose框架 | 先用OKhttp下载远程音频文件再使用ExoPlayer播放
使用 Kotlin 的 Jetpack Compose 开发安卓应用时,可以结合 OkHttp 下载远程音频文件和 ExoPlayer 进行播放。在 `build.gradle` 添加相关依赖后,示例代码展示了如何下载音频并用 ExoPlayer 播放。代码包括添加依赖、下载文件、播放文件及简单的 Compose UI。注意,示例未包含完整错误处理和资源释放,实际应用需补充这些内容。
|
21天前
|
前端开发 JavaScript 测试技术
|
2月前
|
数据库 Android开发
Android数据库框架-GreenDao入门,2024年最新flutter 页面跳转动画
Android数据库框架-GreenDao入门,2024年最新flutter 页面跳转动画
Android数据库框架-GreenDao入门,2024年最新flutter 页面跳转动画
|
2月前
|
开发框架 架构师 安全
android快速开发框架,建议收藏
android快速开发框架,建议收藏
|
27天前
|
XML Java API
54. 【Android教程】图片资源:Drawable
54. 【Android教程】图片资源:Drawable
17 0