做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. 菜鸟学习Ado.net笔记一:Ado.net学习之SqlHelper类

    using System; using System.Collections.Generic; using System.Text; using System.Data.SqlClient; usin ...

  2. javascript基础之javascript的存在形式和js代码块在页面中的存放位置

    1.存在形式 文件 如: <script src='js/jc.js'></script> 前页面 <script type='text/javascript'>a ...

  3. css文件和js文件后面带一个问号

    经常看一些网站页面源代码中的css文件和js文件后面带一个问号,后面跟着一连串数字或字符,这是干什么用的? 这个方法我也用过,而且很好用?,它的作用有两个:1.作为版本号,让自己方便记忆.查找:2.作 ...

  4. gis基本概念之"投影变换"-浅谈

    目录 1,概述 2,常用的投影方法有 正解变换 反解变换 数值变换 3,定义投影 4,投影变换 1,栅格(投影变换) 2,要素(投影变换) 注意 1,概述 因为GIS描述的是位于地球表面的信息,所以根 ...

  5. PHP 杂项 函数

    安装 杂项函数是 PHP 核心的组成部分.无需安装即可使用这些函数. Runtime 配置 杂项函数的行为受 php.ini 文件中的设置的影响. 杂项配置选项: 名称 默认 描述 可更改 ignor ...

  6. JQuery 解析xml

    JQuery 可以通过 $.get() 或 $.post() 方法来加载 xml.     JQuery 解析 XML 与解析 DOM 一样, 可以使用 find(), children() 等函数来 ...

  7. javascript访问级别

    JavaScript中没有官方的访问级别语法,JavaScript没有类似于Java语言智能搞得private或protected这样的访问级别关键字,默认情况下,,对象中所有的成员都是公有和可访问的 ...

  8. 由浅入深完全掌握Ajax

    n年前,如果不知道 XML,您就是一只无人重视的丑小鸭.十八个月前,Ruby 成了关注的中心,不知道 Ruby 的程序员只能坐冷板凳了.今天,如果想跟上最新的技术时尚,那您的目标就是 Ajax. 但是 ...

  9. 【行为型】Chain of responsibility模式

    职责链模式将对象的请求处理组成链式结构,并将请求按链式结构逐个传递下去,直接被其中的某个处理者处理为止.由此可知,职责链模式的适用场合是对指定请求,可以有多个请求处理者(或称为请求响应者),但用户并不 ...

  10. python ciscolib模块

    python的第三方模块ciscolib可以登录交换机执行相关命令 ciscolib下载地址: https://github.com/nickpegg/ciscolib 常见用法如下: switch ...