做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. hdu 2544

    #include <iostream> #include <cstdio> #define INF 9999999 //#define INF 0x3f3f3f3 using ...

  2. AngularJs学习html转义

    MainApp.directive('ngHtml', function () { function watch(scope, el, watchExp){ scope.$watch(watchExp ...

  3. Tab标签栏 切换 权威总结

    angular的标签栏,有两种方法实现: 内容全部加载到页面中,再利用ng-show指令. 将每一块要加载的内容做成模板,利用ng-if指令加载. 用bootstrap的tab组件 用angular的 ...

  4. 商品标签例子——CSS3 transform 属性

    积累很重要.从此开始记录前端生涯的点滴.... <!DOCTYPE html><html lang="en"><head> <meta c ...

  5. angularjs中ng-attr的用法

    <!DOCTYPE html> <html lang="zh-CN" ng-app="app"> <head> <me ...

  6. icon font

    简而言之,就是: 使用 特殊字符 + (使用@font-face)自定义的字体 来代替图片文件显示图标. 关于@font-face, 参考来自W3CPLUS 的详细解释: css3 @font-fac ...

  7. 你好,C++(23) 4.4.2 工资程序成长记:用数组处理批量数据,用循环结构执行重复动作

    4.4  从语句到程序 了解了各种表达式和语句之后,就相当于掌握了写作文要用到的词语和句子,但是,仅有词语和句子是无法构成一篇有意义的文章的.要完成一篇文章,先需要确定这篇文章的结构,是先分述再总述, ...

  8. 磁盘阵列RAID

                                                                                  磁盘阵列RAID 年提出的.RAID名为独立 ...

  9. idea intellij 快捷键(ubuntu版本)

    S + C + T 创建测试类 A + F12 开启终端 C + F12 查看类中的方法属性 ----随时更新,记录快捷方式

  10. 清除IE下链接虚线框

    方法一:利用javascript的onfocus事件,实现如下: Html代码 <a href="http://www.www.baidu.com"  onfocus=&qu ...