[TOC]
inflate 一詞本意是膨脹、充氣,在 LayoutInflater 里我們可以把它理解為加載出來的意思,LayoutInflater 即布局加載器,從指定的 xml 資源文件中加載出具有層次的視圖結構。inflate 方法應該是我們日常碼代碼中最常用的方法之一,今天對 inflate 方法進行分析。
```java
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_timed_list, parent, false);
```
上面這一行代碼大家都很熟悉,就是從布局文件中加載 View 到父容器中。那么幾個參數又分別代表了什么呢?我們一一來看:
# from()方法
LayoutInflater 的 from 方法,從給定的 Context 獲取到 LayoutInflater,這個就是調用系統的 getSystemService 方法:
```java
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
```
另外通過 Activity 實例的 getLayoutInflater 方法同樣可以獲取到 LayoutInflater實例。
# inflate()方法
## 方法重載
LayoutInflater 的 inflate 方法共有 4 種重載:
```java
// 方法A
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
// 方法B
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
return inflate(parser, root, root != null);
}
// 方法C
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
...
}
// 方法D
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
...
}
```
方法A和方法B很簡單,分別調用了方法C和方法D。方法C和方法D的區別在于第一個參數,方法C接收的為布局ID,方法D接收的為布局資源解釋器XmlResourceParser。
```java
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
//...
final XmlResourceParser parser = res.getLayout(resource);
//...
return inflate(parser, root, attachToRoot);
}
```
其實方法C拿到布局ID后也是生成XmlResourceParser再調用方法D。
## 源碼分析
雖然方法C最終調用的是方法D,但我們調用inflate方法時一般調用方法C,很少直接調用方法D的。
先來看看方法C幾個參數的含義:
* resource:想要加載的 xml 布局資源文件的 ID
* root:當 attachToRoot 為 true 時,root 即為 inflate 方法加載出來的 View 的根布局;不然 root 僅僅為將要加載出來的 View 提供一組 LayoutParams 參數而已
* attachToRoot:這個值指即將加載出來的 View 是否會附加到上面的 root 中
* 返回值:inflate 方法的返回值是一個 View,指即將加載出來 視圖結構的根 View。如果上面提供了 root,并且 attachToRoot 為真時,返回的就是 root;否則為即將加載出來視圖結構的根 View
看下方法C的源碼:
```java
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
...
// 根據布局資源文件得到一個 XmlResourceParser
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
```
看到調用了 inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)方法,接下來我們只看看關鍵的代碼:
```java
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
View result = root;
// 創建View
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
// 1、root不為空時
if (root != null) {
// 根據xml配置的屬性,生成View的LayoutParams
params = root.generateLayoutParams(attrs);
// 創建出的View不附加到root時
if (!attachToRoot) {
// 1.1、把剛生成的LayoutParams設置給View(一會兒View直接就是返回值了)
temp.setLayoutParams(params);
}
}
// 遞歸加載所有子 View
// rInflateChildren(parser, temp, attrs, true);
// 1.2、root不為空,且attachToRoot為true時,把View添加到root中
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// 2、root為空
if (root == null || !attachToRoot) {
result = temp;
}
return result;
}
```
## 整體總結
可以看到:
1、root不為空時,根據xml中配置的屬性,生成LayoutParams。
* 1.1、加載出的View不附加到root時,直接給View設置LayoutParams,root就沒事了
* 1.2、加載出的View附加到root時,把View添加到root中,使用該LayoutParams
2、root為空時,View直接創建出來就沒了,就沒設置LayoutParams那一步了
3、返回值問題
* 3.1、root為空或root不空但不附加到root時,直接返回創建出來的View
* 3.2、root不空且附加到root時,返回的是root(當然View已經附加到里面了)
> 備注
現在回頭來看看構造方法C中的三個參數的作用:
1、resource制定了資源文件的ID,必不可少
2、root僅僅是為了給View生成LayoutParams,其他沒啥用了
3、attachToRoot決定了要不要把View附加到root中
- 導讀
- Java知識
- Java基本程序設計結構
- 【基礎知識】Java基礎
- 【源碼分析】Okio
- 【源碼分析】深入理解i++和++i
- 【專題分析】JVM與GC
- 【面試清單】Java基本程序設計結構
- 對象與類
- 【基礎知識】對象與類
- 【專題分析】Java類加載過程
- 【面試清單】對象與類
- 泛型
- 【基礎知識】泛型
- 【面試清單】泛型
- 集合
- 【基礎知識】集合
- 【源碼分析】SparseArray
- 【面試清單】集合
- 多線程
- 【基礎知識】多線程
- 【源碼分析】ThreadPoolExecutor源碼分析
- 【專題分析】volatile關鍵字
- 【面試清單】多線程
- Java新特性
- 【專題分析】Lambda表達式
- 【專題分析】注解
- 【面試清單】Java新特性
- Effective Java筆記
- Android知識
- Activity
- 【基礎知識】Activity
- 【專題分析】運行時權限
- 【專題分析】使用Intent打開三方應用
- 【源碼分析】Activity的工作過程
- 【面試清單】Activity
- 架構組件
- 【專題分析】MVC、MVP與MVVM
- 【專題分析】數據綁定
- 【面試清單】架構組件
- 界面
- 【專題分析】自定義View
- 【專題分析】ImageView的ScaleType屬性
- 【專題分析】ConstraintLayout 使用
- 【專題分析】搞懂點九圖
- 【專題分析】Adapter
- 【源碼分析】LayoutInflater
- 【源碼分析】ViewStub
- 【源碼分析】View三大流程
- 【源碼分析】觸摸事件分發機制
- 【源碼分析】按鍵事件分發機制
- 【源碼分析】Android窗口機制
- 【面試清單】界面
- 動畫和過渡
- 【基礎知識】動畫和過渡
- 【面試清單】動畫和過渡
- 圖片和圖形
- 【專題分析】圖片加載
- 【面試清單】圖片和圖形
- 后臺任務
- 應用數據和文件
- 基于網絡的內容
- 多線程與多進程
- 【基礎知識】多線程與多進程
- 【源碼分析】Handler
- 【源碼分析】AsyncTask
- 【專題分析】Service
- 【源碼分析】Parcelable
- 【專題分析】Binder
- 【源碼分析】Messenger
- 【面試清單】多線程與多進程
- 應用優化
- 【專題分析】布局優化
- 【專題分析】繪制優化
- 【專題分析】內存優化
- 【專題分析】啟動優化
- 【專題分析】電池優化
- 【專題分析】包大小優化
- 【面試清單】應用優化
- Android新特性
- 【專題分析】狀態欄、ActionBar和導航欄
- 【專題分析】應用圖標、通知欄適配
- 【專題分析】Android新版本重要變更
- 【專題分析】唯一標識符的最佳做法
- 開源庫源碼分析
- 【源碼分析】BaseRecyclerViewAdapterHelper
- 【源碼分析】ButterKnife
- 【源碼分析】Dagger2
- 【源碼分析】EventBus3(一)
- 【源碼分析】EventBus3(二)
- 【源碼分析】Glide
- 【源碼分析】OkHttp
- 【源碼分析】Retrofit
- 其他知識
- Flutter
- 原生開發與跨平臺開發
- 整體歸納
- 狀態及狀態管理
- 零碎知識點
- 添加Flutter到現有應用
- Git知識
- Git命令
- .gitignore文件
- 設計模式
- 創建型模式
- 結構型模式
- 行為型模式
- RxJava
- 基礎
- Linux知識
- 環境變量
- Linux命令
- ADB命令
- 算法
- 常見數據結構及實現
- 數組
- 排序算法
- 鏈表
- 二叉樹
- 棧和隊列
- 算法時間復雜度
- 常見算法思想
- 其他技術
- 正則表達式
- 編碼格式
- HTTP與HTTPS
- 【面試清單】其他知識
- 開發歸納
- Android零碎問題
- 其他零碎問題
- 開發思路