做Android应用的人都知道,要一个apk适用多个不同的手机屏幕是很容易的,就是在项目的res文件夹下面有多套相关的资源文件。程序运行的时候,Android系统会根据当前设备的信息去加载不同文件夹下的资源文件。但是Android系统是怎么做到这一点的呢?上网上搜了一下,很少有这方便的介绍,只好自己研究下代码了。下面是我研究代码得到的结果(正确性有待确认),在这里分享一下。

这里以ICS上在Activity的onCreate()方法里面调用setContentView(int resourceID)为例,介绍一下系统如何根据我们的id(R.layout.xxxx)找到合适的layout文件进行解析加载:

如果你的res下面有三种不同的layout:layout, layout-sw480dp和 layout-sw600dp,这里的sw<N>dp表示这个layout文件夹下面的布局文件只有在设备短边的最小宽带为N时才加载。你的设备是800x480的分辨率,那么这个apk安装在你的设备上就会加载 layout-sw480dp里面的布局文件。下面是framework的java层调用链:

Activity.setContentView(int resourceID) -> PhoneWindow.setContentView(int resourceID) -> LayoutInflater.inflate(int resource, ViewGroup root) -> LayoutInflater.inflate(int resource, ViewGroup root, boolean attachToRoot) -> Resources.getLayout(int id) -> Resources.loadXmlResourceParser(int id, String type) -> Resources.getValue(int id, TypedValue outValue, boolean resolveRefs) -> AssetManager.getResourceValue(int ident, int density, TypedValue outValue, boolean resolveRefs) -> AssetManager.loadResourceValue(int ident, short density, TypedValue outValue, boolean resolve)

在上面的掉用链中:

1. 最后加载的是哪个xml是由Resources.getValue(int id, TypedValue outValue, boolean resolveRefs)调用完成之后的outValue.string决定的,因为outValue.string的值就是你的资源文件的具体路径,如:

  1) xxx/values/xxx.xml

  2) xxx/layout-sw600dp/xxx.xml

2. AssetManager.loadResourceValue()调的是frameworks/base/core/jni/android_util_AssetManager.cpp里面的native方法, 如何获得正确的outValue值,在native方法俩面主要有以下几步:

  1) 调用frameworks/base/libs/utils/ResourceTypes.cpp 的ResTable::getResource(),遍历所有资源文件

  2) 在ResTable::getResource()里面调用ResTable::getEntry()来确定资源文件来自哪个entry,即layout,或者layout-sw<N>dp,由此可见,ResTable::getEntry()是我们这个问题的关键

  3) 在ResTable::getEntry()里面:

    a) 首先获取本设备的configurion信息,屏幕分辨率,屏幕大小,locale,横竖屏等。

    b) 根据得到的本设备的configurion信息,过滤掉不适应本设备的entry,比如设备是800x480的,那么超过此分辨率的资源(例:layout-sw600dp)就要被过滤掉,实现在frameworks/base/include/utils/ResourceTypes.h中ResTable_config的match函数中

    c) 对过滤后的resource进行最佳适配,找到最符合的entry文件。因为之前已经将不符合的,即大分辨率的entry已经被过滤掉了,所以这里就找剩下的最大的就是最佳适配的。实现在frameworks/base/include/utils/ResourceTypes.h中ResTable_config的isBetterThan()函数中。

3. 我做了一个尝试,就是想让800x480分辨率的设备上的应用都加载 layout-sw600dp里面的资源文件。所以将上面b)步骤的frameworks/base/include/utils/ResourceTypes.h里面ResTable_config的match函数改动如下:

/*if (smallestScreenWidthDp != 0
              && smallestScreenWidthDp > settings.smallestScreenWidthDp){
          return false;
}*/
 
if (smallestScreenWidthDp != 0
              && smallestScreenWidthDp > 600) {
          return false;
}

我将settings.smallestScreenWidthDp强制换成了600,这样的话,所有比600dp小的(包含600)在内的资源文件在做过滤时就被保留了下来,而c)步骤不做检查,只找最大的,所以layout-sw600dp就成了系统认为的“最合适”的资源问价了。

将重新编译frameworks/base/libs/utils/生成的lib库push到/system/libs下面,再重启手机,然后启动上述应用,就可以了看见程序加载的layout-sw600dp的ui了。

Android系统如何实现UI的自适应的更多相关文章

  1. android系统如何自适应屏幕大小

    1.屏幕相关概念 1.1分辨率 是指屏幕上有横竖各有多少个像素 1.2屏幕尺寸 指的是手机实际的物理尺寸,比如常用的2.8英寸,3.2英寸,3.5英寸,3.7英寸 android将屏幕大小分为四个级别 ...

  2. Android系统自适应屏幕大小

    1.屏幕相关概念1.1分辨率是指屏幕上有横竖各有多少个像素1.2屏幕尺寸指的是手机实际的物理尺寸,比如常用的2.8英寸,3.2英寸,3.5英寸,3.7英寸android将屏幕大小分为四个级别(smal ...

  3. Android系统Surface机制的SurfaceFlinger服务渲染应用程序UI的过程分析

    参考:Android系统Surface机制的SurfaceFlinger服务渲染应用程序UI的过程分析 一句话概括一下Android应用程序显示的过程:Android应用程序调用SurfaceFlin ...

  4. 苹果IOS与谷歌 android系统的UI设计原则

    一.苹果为IOS的界面设计提出了六大原则: 1.整体美学 整体美学指的是一个应用的表现和行为与它的功能完美集成,传达连贯的信息. 人们关心一个应用是否提供它承诺的功能,但他们也被应用的外观和行为强烈影 ...

  5. Android系统UI交互控件Action Bar初探

    过年期间,Google正式宣布取消Android系统中MENU键的使用,也就是基于Android 4.0系统的手机都应没有MENU这一固定按键.这无疑是个变革性的改动,在我眼中,这似乎把Android ...

  6. [Android]官网《UI/Application Exerciser Monkey》中文翻译

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5049041.html 翻译自 Android Develope ...

  7. Android系统自带APP分析——短信app

    Android操作系统本身就是一个巨大的开源软件仓库,熟悉它既可以了解到Android系统的设计框架,也可以获得高效的应用程序编写方式.本文所分析的源码来自于Google官方的AOSP源码4.0.1_ ...

  8. 深入浅出 - Android系统移植与平台开发(六)- 为Android启动加速

    作者:唐老师,华清远见嵌入式学院讲师. Android的启动速度一直以来是他的诟病,虽然现在Android设备的硬件速度越来越快,但是随着新 版本的出现,其启动速度一直都比较慢,当然,作为程序员,我们 ...

  9. 从Android系统出发,分析Android控件构架

    从Android系统出发,分析Android控件构架 Android中所有的控件追溯到根源,就是View 和ViewGroup,相信这个大家都知道,但是大家也许会不太清楚它们之间的具体关系是什么,在A ...

随机推荐

  1. GSON 示例代码 实用版

    去除所有格式的json字符串 {"data":[{"friend":[{"address":"广州","nam ...

  2. mysql的limit性能,数据库索引问题,dblog问题

    mysql的limit性能,数据库索引问题,dblog问题,redis学习 继续学习. dblog实际上是把日志记录在另一个数据库里面. 问题1: 一张表定义了5个索引,但是sql语句中用到了3个有索 ...

  3. asp.net微信开发第二篇----消息应答

    当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上. 请注意: 1.关于重试的消息排重,推荐使用msgid排重. 2.微信服务器在五秒内收不到响应会断掉连接 ...

  4. MySQL忘记root密码的解决方案

    在实际操作中忘记MySQL的root密码是一件令人很头痛的事情,不要急以下的文章就是介绍MySQL的root密码忘记的时候解决方案,我们可以对其进行如下的步骤重新设置,以下就是文章的详细内容描述.   ...

  5. 自动加载类PHP中spl_autoload_register函数的用法

    spl_autoload_register(PHP 5 >= 5.1.2) spl_autoload_register — 注册__autoload()函数 说明bool spl_autoloa ...

  6. 高放的c++学习笔记之类

    类的基本思想是数据抽象和封装1.this 成员函数通过一个名为this的额外隐式参数来访问调用它的对象,当我们调用一个函数的时候,用请求该函数的对象的初始化this. 如果某个类的名字为sale,某个 ...

  7. 使用2to3转换python代码

    如果要把python2编译器下的代码转换升级到python3编译器,可以使用python自带的 2to3工具进行转化: windows下转化: doc 命令窗口: >> python  C ...

  8. POJ2955:Brackets(区间DP)

    Description We give the following inductive definition of a “regular brackets” sequence: the empty s ...

  9. 移动端(html5)微信公众号下用keyup实时监控input值的变化无效

    搜索框依据用户输入的值实时检索,一开始自然而然想到keyup,在拼音状态时,啥问题也没有, 问题1:切换到中文输入法,问题出来了,keyup事件不灵便了,后来在网上搜了下,找到了思路, 问题2:微信公 ...

  10. Sencha Architect 激活方法

     Sencha Architect 2是ExtJS和Sencha Touch的官方可视化IDE工具.最新版本是2.2,说是破解,其实是修改License来实现无限试用而已. 1.先下载安装官方软件,大 ...