Android View#post()源碼分析

文章目錄

  • Android View#post()源碼分析
    • 概述
    • onCreate和onResume不能獲取View的寬高
    • post可以獲取View的寬高
    • 總結

Android View#post()源碼分析

概述

在 Activity 中,在 onCreate() 和 onResume() 中是無法獲取 View 的寬高,可以通過 View#post() 獲取 View 的寬高。

onCreate和onResume不能獲取View的寬高

Activity 的生命周期都是在 ActivityThread 中,當調用 startActivity() ,最終會調用 ActivityThread#performLaunchActivity()。

// ActivityThread#performLaunchActivity()
// 核心代碼:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {Activity activity = null;java.lang.ClassLoader cl = appContext.getClassLoader();// 通過反射新建一個Activityactivity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);try {if (activity != null) {// 創建并初始化Windowactivity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.activityConfigCallback,r.assistToken, r.shareableActivityToken);r.activity = activity;if (r.isPersistable()) {// 回調Activity#onCreate()mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}            } }return activity;
}
// ActivityThread#handleResumeActivity()
// 核心代碼:
public void handleResumeActivity()(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {// 最終會回調Activity#onResume()if (!performResumeActivity(r, finalStateRequest, reason)) {return;}final Activity a = r.activity;if (r.window == null && !a.mFinished && willBeVisible) {r.window = r.activity.getWindow();View decor = r.window.getDecorView();decor.setVisibility(View.INVISIBLE); // 設置不可見ViewManager wm = a.getWindowManager();WindowManager.LayoutParams l = r.window.getAttributes();a.mDecor = decor;l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;l.softInputMode |= forwardBit;if (r.mPreserveWindow) {a.mWindowAdded = true;r.mPreserveWindow = false;ViewRootImpl impl = decor.getViewRootImpl();if (impl != null) {impl.notifyChildRebuilt();}}if (a.mVisibleFromClient) {if (!a.mWindowAdded) {a.mWindowAdded = true;// 添加View,開始View的操作wm.addView(decor, l);} else { a.onWindowAttributesChanged(l);}} }   
}

說明:Activity 先執行 onCreate(),再執行 onResume(),最后才調用 wm.addView() 將 DecorView 添加到視圖中,也就是從這里才開始執行 View 測量布局繪制流程。簡單說 View 的流程晚于 onResume()。

post可以獲取View的寬高

// View#post()
public boolean post(Runnable action) {final AttachInfo attachInfo = mAttachInfo;if (attachInfo != null) {// 如果attachInfo不為null,表示View已經添加到Window,直接通過Handler發送到主線程隊列return attachInfo.mHandler.post(action);}// 如果attachInfo為null,表示View未添加到Window,暫存在mRunQueue中getRunQueue().post(action);return true;
}private HandlerActionQueue getRunQueue() {if (mRunQueue == null) {mRunQueue = new HandlerActionQueue();}return mRunQueue;
}

說明:在 onCreate() 和 onResume() 中調用 View#post(),最終都會調用 getRunQueue().post(action)。

wm.addView(decor, l) 執行流程:

  • 調用 WindowManagerImpl#addView()。
  • 調用 WindowManagerGlobal#addView()。
  • 執行 new ViewRootImpl,創建 root 對象(布局管理器),并在內部創建 mAttachInfo 對象、Handler 對象。
  • 調用 ViewRootImpl#setView()。
// ViewRootImpl#setView()
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {synchronized (this) {if (mView == null) {mView = view;// 請求布局,最終調用ViewRootImpl#performTraversals()requestLayout();           try {// 通過Binder調用WMS添加Windowres = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), userId,mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,mTempControls);               }   }}
}
// ViewRootImpl#performTraversals()
private void performTraversals() {final View host = mView;// 調用View#dispatchAttachedToWindow()分發mAttachInfo    host.dispatchAttachedToWindow(mAttachInfo, 0);// 測量流程performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);// 布局流程performLayout(lp, mWidth, mHeight);// 繪制流程performDraw()
}
// View#dispatchAttachedToWindow()
void dispatchAttachedToWindow(AttachInfo info, int visibility) {mAttachInfo = info;// 執行緩存任務if (mRunQueue != null) {mRunQueue.executeActions(info.mHandler);mRunQueue = null;}  
}
// HandlerActionQueue#executeActions()
public class HandlerActionQueue {private HandlerAction[] mActions;public void executeActions(Handler handler) {synchronized (this) {final HandlerAction[] actions = mActions;for (int i = 0, count = mCount; i < count; i++) {final HandlerAction handlerAction = actions[i];handler.postDelayed(handlerAction.action, handlerAction.delay);}mActions = null;mCount = 0;}}
}

說明:執行 mRunQueue.executeActions(),會將所有緩存的任務發送到 handler 中,等待主線程執行完 performTraversals() 方法后,就會執行 mActions 中的任務,這時就可以獲取到 View 的寬高。

總結

執行流程:

  • Activity#onCreate()
  • Activity#onResume()
  • WindowManagerImpl#addView()
  • new ViewRootImpl()
  • ViewRootImpl#setView()
  • View的測量流程
  • View的布局流程
  • View的繪制流程
  • WMS添加Window
  • 獲取View的寬高

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/79639.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/79639.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/79639.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SecureCrt設置顯示區域橫列數

1. Logical rows //邏輯行調顯示區域高度的 一般超過50就全屏了 2. Logical columns //邏輯列調顯示區域寬度的 3. Scrollback buffer //緩沖區大小

最短路徑-Dijkstra算法板子(java)

自己把Dijkstra的板子整理了一下&#xff0c;也方便自己后續做題&#xff0c;在此做個記錄。 Dijkstra基本上都會需要這些變量&#xff1a; dist[]&#xff1a;記錄各個節點到起始節點的最短權值 path[]&#xff1a;記錄各個節點的上一個節點(用來聯系該節點到起始節點的路徑)…

PostgreSQL數據庫的array類型

PostgreSQL數據庫相比其它數據庫&#xff0c;有很多獨有的字段類型。 比如array類型&#xff0c;以下表的pay_by_quarter與schedule兩個字段便是array類型&#xff0c;即數組類型。 CREATE TABLE sal_emp (name text,pay_by_quarter integer[],schedule t…

centos的根目錄占了大量空間怎么辦

問題 當根目錄磁盤不夠時&#xff0c;就必須刪除無用的文件了 上面的&#xff0c;如果刪除/usr 或/var是可以釋放出系統盤的 定位占空間大的文件 經過命令&#xff0c;一層層查哪些是占磁盤的。 du -sh /* | sort -rh | head -n 10 最終排查&#xff0c;是有個系統日志占了20…

PostgreSQL存儲過程“多態“實現:同一方法名支持不同參數

引言 在傳統編程語言中&#xff0c;方法重載&#xff08;同一方法名不同參數&#xff09;是實現多態的重要手段。但當我們將目光轉向PostgreSQL數據庫時&#xff0c;是否也能在存儲過程&#xff08;函數&#xff09;中實現類似的功能&#xff1f;本文將深入探討PostgreSQL中如…

快速學會Linux的WEB服務

一.用戶常用關于WEB的信息 什么是WWW www是world wide web的縮寫&#xff0c;及萬維網&#xff0c;也就是全球信息廣播的意思 通常說的上網就是使用www來查詢用戶所需要的信息。 www可以結合文字、圖形、影像以及聲音等多媒體&#xff0c;超鏈接的方式將信息以Internet傳遞到世…

Windows玩游戲的時候,一按字符鍵就顯示桌面

最近打賽伯朋克 2077 的時候&#xff0c;不小心按錯鍵了&#xff0c;導致一按字符鍵就顯示桌面。如下&#xff1a; 一開始我以為是輸入法的問題&#xff08;相信打游戲的人都知道輸入法和奔跑鍵沖突的時候有多煩&#xff09;&#xff0c;但是后來解決半天發現并不是。在網上搜…

【測試開發】概念篇 - 從理解需求到認識常見開發、測試模型

&#x1f4e2;博客主頁&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客倉庫&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;歡迎點贊 &#x1f44d; 收藏 ?留言 &#x1f4dd; 如有錯誤敬請指正&#xff01; &…

核函數(Kernel function)

核函數 核函數在GPU上進行并行執行 注意: 限定詞__global__修飾 [雙下劃線]返回值必須是void 形式: _global_ void kernel_function( argument arg){ ? printf(“hello world from the GPU\n”); } void __global__kernel_function( argument arg){ ? printf(“hello worl…

數據結構與算法:區間dp

前言 區間dp也是動態規劃里很重要的一部分。 一、內容 區間dp的根本原理就是把大范圍問題分解成若干小范圍的問題去求解。一般來講,常見的用法有對于兩側端點去展開可能性和對于范圍上的劃分點去展開可能性。 二、題目 1.讓字符串成為回文串的最少插入次數 class Soluti…

AI Agent 入門指南:從 LLM 到智能體

AI. AI. AI. 最近耳朵里是不是總是被這些詞轟炸&#xff1f;特別是“Agent”、“AI Agent”、“智能體”、“Agentic”…… 感覺一夜之間&#xff0c;AI 就從我們熟悉的聊天框里蹦出來&#xff0c;要擁有“獨立思考”和“自主行動”的能力了&#xff1f; 說實話&#xff0c;一…

開啟docker中mysql的binlog日志

1.登陸docker服務器,輸入docker ps查看服務: 2.進入mysql服務 進入到mysql的服務容器后,輸入mysql -u*** -p***登陸 mysql 客戶端查看是否開啟binlog 輸入 : show variables like log_bin; 3.輸入quit退出mysql客戶端 4.之后在docker的mysql服務容器里查詢mysql的配置文件所在…

Kotlin 中 List 和 MutableList 的區別

在 Kotlin 中&#xff0c;List 和 MutableList 是兩種不同的集合接口&#xff0c;核心區別在于可變性。 Kotlin 集合框架的重要設計原則&#xff1a;通過接口分離只讀&#xff08;read - only&#xff09;和可變&#xff08;mutable&#xff09;操作&#xff0c;以提高代碼的安…

【能力比對】K8S數據平臺VS數據平臺

&#x1f525;&#x1f525; AllData大數據產品是可定義數據中臺&#xff0c;以數據平臺為底座&#xff0c;以數據中臺為橋梁&#xff0c;以機器學習平臺為中層框架&#xff0c;以大模型應用為上游產品&#xff0c;提供全鏈路數字化解決方案。 ?AllData數據中臺官方平臺&…

Fastjson 從多層級的JSON數據中獲取特定字段的值

使用 Fastjson 的 JSONPath.eval 可以通過 JSONPath 表達式直接定位多層級 JSON 中的目標字段&#xff0c;避免逐層調用 getJSONObject() 的繁瑣操作。以下是具體實現方法和示例&#xff1a; 核心思路 通過 JSONPath.eval 方法&#xff0c;傳入 JSON 對象&#xff08;或 JSON…

端口安全基本配置

1.top圖 2.交換機配置 交換機swa <SWA> system-view [SWA] vlan batch 10 20[SWA] interface GigabitEthernet0/0/1 [SWA-GigabitEthernet0/0/1] port link-type trunk [SWA-GigabitEthernet0/0/1] port trunk allow-pass vlan 10[SWA] interface GigabitEthernet0/0/2 …

hadoop集群建立

建立Hadoop集群的步驟指南 建立Hadoop集群需要系統規劃和多個步驟的配置。以下是詳細的建立流程&#xff1a; 一、前期準備 硬件需求 多臺服務器(至少3臺&#xff0c;1主2從) 每臺建議配置&#xff1a;至少4核CPU&#xff0c;8GB內存&#xff0c;100GB硬盤 穩定的網絡連接(…

從零開始學java--集合類(2)

集合類 目錄 集合類 Queue 隊列的使用&#xff1a; 雙端隊列&#xff08;Deque&#xff09; Map和Set 概念&#xff1a; 模型&#xff1a; Map 常見方法說明&#xff1a; 注意&#xff1a; TreeMap和HashMap的區別&#xff1a; Set 常見方法說明&#xff1a; 注…

【HarmonyOS 5】鴻蒙發展歷程

【HarmonyOS 5】鴻蒙發展歷程 一、鴻蒙 HarmonyOS 版本年代記 鴻蒙 1.0&#xff1a; 2019 年 8 月 9 日&#xff0c;華為在開發者大會上正式發布鴻蒙 1.0 系統&#xff0c;這一版本首次應用于華為榮耀智慧屏產品中&#xff0c;標志著華為正式進軍操作系統領域。該版本初步展現…

SpringBoot教學管理平臺源碼設計開發

概述 基于SpringBoot框架開發的??教學管理平臺??完整項目&#xff0c;幫助開發者快速搭建在線教育平臺。該系統包含學生端、教師端和管理后臺&#xff0c;實現了課程管理、隨堂測試、作業提交等核心功能&#xff0c;是學習SpringBoot開發的優質案例。 主要內容 1. 系統架…