插件化框架设计(二) 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 获取属性值。

相关文章
|
3月前
|
物联网 区块链 vr&ar
未来已来:探索区块链、物联网与虚拟现实技术的融合与应用安卓与iOS开发中的跨平台框架选择
【8月更文挑战第30天】在科技的巨轮下,新技术不断涌现,引领着社会进步。本文将聚焦于当前最前沿的技术——区块链、物联网和虚拟现实,探讨它们各自的发展趋势及其在未来可能的应用场景。我们将从这些技术的基本定义出发,逐步深入到它们的相互作用和集成应用,最后展望它们如何共同塑造一个全新的数字生态系统。
|
4月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台框架解析
在移动应用开发的广阔舞台上,安卓和iOS一直是两大主角。随着技术的进步,开发者们渴望能有一种方式,让他们的应用能同时在这两大平台上运行,而不必为每一个平台单独编写代码。这就是跨平台框架诞生的背景。本文将探讨几种流行的跨平台框架,包括它们的优势、局限性,以及如何根据项目需求选择合适的框架。我们将从技术的深度和广度两个维度,对这些框架进行比较分析,旨在为开发者提供一个清晰的指南,帮助他们在安卓和iOS的开发旅程中,做出明智的选择。
|
17天前
|
算法 JavaScript Android开发
|
26天前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
96 1
|
2月前
|
前端开发 Java 数据库
💡Android开发者必看!掌握这5大框架,轻松打造爆款应用不是梦!🏆
在Android开发领域,框架犹如指路明灯,助力开发者加速应用开发并提升品质。本文将介绍五大必备框架:Retrofit简化网络请求,Room优化数据库访问,MVVM架构提高代码可维护性,Dagger 2管理依赖注入,Jetpack Compose革新UI开发。掌握这些框架,助你在竞争激烈的市场中脱颖而出,打造爆款应用。
356 3
|
2月前
|
编译器 Android开发 开发者
带你了解Android Jetpack库中的依赖注入框架:Hilt
本文介绍了Hilt,这是Google为Android开发的依赖注入框架,基于Dagger构建,旨在简化依赖注入过程。Hilt通过自动化的组件和注解减少了DI的样板代码,提高了应用的可测试性和可维护性。文章详细讲解了Hilt的主要概念、基本用法及原理,帮助开发者更好地理解和应用Hilt。
77 8
|
3月前
|
设计模式 Java Android开发
探索安卓应用开发:从新手到专家的旅程探索iOS开发中的SwiftUI框架
【8月更文挑战第29天】本文旨在通过一个易于理解的旅程比喻,带领读者深入探讨安卓应用开发的各个方面。我们将从基础概念入手,逐步过渡到高级技术,最后讨论如何维护和推广你的应用。无论你是编程新手还是有经验的开发者,这篇文章都将为你提供有价值的见解和实用的代码示例。让我们一起开始这段激动人心的旅程吧!
|
3月前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
如何使用Amlogic T972安卓9.0系统上的misc框架来简化驱动程序开发,通过misc框架自动分配设备号并创建设备文件,从而减少代码量并避免设备号冲突。
46 0
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
|
3月前
|
存储 前端开发 Java
Android MVVM框架详解与应用
在Android开发中,随着应用复杂度的增加,如何有效地组织和管理代码成为了一个重要的问题。MVVM(Model-View-ViewModel)架构模式因其清晰的结构和高效的开发效率,逐渐成为Android开发者们青睐的架构模式之一。本文将详细介绍Android MVVM框架的基本概念、优势、实现流程以及一个实际案例。
105 0
|
3月前
|
监控 Java 开发工具
### 绝招揭秘!Android平台GB28181设备接入端如何实现资源占用和性能消耗的极限瘦身?
【8月更文挑战第14天】本文介绍在Android平台优化GB28181标准下设备接入的性能方法,涵盖环境搭建、SDK集成与初始化。重点讲解内存管理技巧如软引用、按需加载资源,以及通过硬件加速解码视频数据和图像缩放来减轻CPU与GPU负担。同时采用线程池异步处理视频流,确保UI流畅性。这些策略有助于提高应用效率和用户体验。
47 0
下一篇
无影云桌面