[转] Android系统如何实现UI的自适应
原文鏈接:?http://www.cnblogs.com/melaniedeng/archive/2012/05/17/2506869.html
?
?
做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了。
轉載于:https://www.cnblogs.com/jalenwang/archive/2012/09/01/android-resouces.html
總結
以上是生活随笔為你收集整理的[转] Android系统如何实现UI的自适应的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从M2M迁移到IIoT工业物联网
- 下一篇: 获取分割后右边的字符串