AccessibilityEvent的生成和處理

在 Android 框架層,AccessibilityEvent 的生成和處理是通過系統的 UI 框架和輔助功能服務框架密切協作來實現的。這個機制涉及幾個關鍵的部分:UI 組件、輔助功能服務、事件監聽和事件分發。以下是對這些部分和它們如何協同工作的詳細解釋:

1 UI框架與事件生成

Android 的 UI 框架允許應用構建交互界面。每個 UI 元素(如按鈕、文本視圖等)都是 View 類的一個實例。當這些視圖發生狀態改變(如被點擊、被滑動等)時,UI 框架負責生成相應的 AccessibilityEvent

  • 事件觸發:當用戶與設備上的視圖交互(如通過觸摸屏點擊或滑動)時,Android 的輸入處理系統會捕捉這些操作并將它們轉換為相應的事件(如觸摸事件)。這些事件隨后被傳遞給相應的視圖進行處理。
  • 事件處理:視圖通過其事件監聽器(如 OnClickListenerOnTouchListener 等)響應這些事件。在事件處理過程中,視圖可以調用 sendAccessibilityEvent(int eventType) 方法來生成相應類型的 AccessibilityEvent

Android 的事件分發系統處理從頂層窗口到具體被點擊視圖的事件傳遞。當一個觸摸事件發生時,系統首先將事件傳遞給頂級視圖,然后通過 dispatchTouchEvent() 方法沿視圖樹向下傳遞到具體的子視圖。在視圖層級中,每個視圖都可以重寫 dispatchTouchEvent 方法來檢測和響應觸摸事件。如果該視圖或其子視圖消費了事件(例如,一個按鈕識別并響應了點擊事件),dispatchTouchEvent 將返回 true。否則,事件將繼續傳遞給視圖層級中的其他視圖。如下的 onClick 方法中已包含如何發送輔助功能事件的代碼。當按鈕被點擊時,除了響應點擊外,還調用了 sendAccessibilityEvent 來發送一個類型為 TYPE_VIEW_CLICKED 的輔助功能事件。

Button button = findViewById(R.id.my_button);
button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 處理點擊事件Toast.makeText(v.getContext(), "Button clicked!", Toast.LENGTH_SHORT).show();// 發送輔助功能事件v.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);}
});

2 AccessibilityEvent 的處理和分發

  • 事件創建:當調用 sendAccessibilityEvent() 方法時,視圖對象會構建一個 AccessibilityEvent,包含事件類型、觸發事件的視圖信息、視圖內容描述、當前狀態等信息。
  • 事件分發:一旦 AccessibilityEvent 被創建,它會被發送到 AccessibilityManager,這是一個系統服務,負責管理所有活動的輔助功能服務。
  • 輔助功能服務AccessibilityManager 將事件分發給所有注冊并啟用的輔助功能服務。這些服務可以通過實現 AccessibilityService 類并重寫 onAccessibilityEvent() 方法來接收和處理這些事件。Android 系統提供了 AccessibilityManager,這是一個系統級服務,作為橋梁在應用的 UI 組件和輔助功能服務之間傳遞信息。
  • 這個服務負責:
  • 接收來自應用視圖的 AccessibilityEvent
  • 管理輔助功能服務的注冊和激活狀態。
  • AccessibilityEvent 分發給所有激活的輔助功能服務。

3 獲取事件相關的信息

在 Android 的輔助功能服務中,有兩種主要方式來獲取與點擊事件相關的信息:通過 event.getText() 和通過 event.getSource() 獲取的 AccessibilityNodeInfo。在實際開發中,選擇哪種方法取決于具體需求和性能考量。對于簡單的文本獲取,使用 event.getText() 可能更合適;而對于需要詳細操作視圖或獲取更多視圖信息的場景,則 AccessibilityNodeInfo 是更好的選擇。例如在微信聊天界面的頂部昵稱點擊事件中,需要使用event.getText()才會獲取到該文本信息。

3.1 使用 event.getText()

這種方法直接從 AccessibilityEvent 對象中獲取與事件相關的文本列表。這種方法簡單直接,但可能不提供完整的上下文信息。

示例代碼:
@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {int eventType = event.getEventType();switch (eventType) {case AccessibilityEvent.TYPE_VIEW_CLICKED:Log.i(TAG, "TYPE_VIEW_CLICKED");// 使用event.getText()獲取與點擊事件關聯的文本信息List<CharSequence> texts = event.getText();String eventText = texts.isEmpty() ? "" : texts.get(0).toString(); // 獲取第一項文本,假設它是主要文本Log.i(TAG, "Clicked text: " + eventText);break;}}

3.2 使用 AccessibilityNodeInfo

這種方法通過 event.getSource() 獲取一個 AccessibilityNodeInfo 對象,該對象代表觸發事件的UI組件。AccessibilityNodeInfo 提供了豐富的信息和操作接口。提供了關于觸發事件視圖的詳細信息,包括視圖的狀態、屬性等。允許進行交互,如點擊、長按等操作。 可以遍歷視圖樹,獲取更多關聯視圖的信息。需要更多的處理和可能的資源回收。對性能要求稍高,因為涉及到對象的創建和回收。

示例代碼:
@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {int eventType = event.getEventType();switch (eventType) {case AccessibilityEvent.TYPE_VIEW_CLICKED:Log.i(TAG, "TYPE_VIEW_CLICKED");// 獲取事件關聯的AccessibilityNodeInfo對象AccessibilityNodeInfo nodeInfo = event.getSource();if (nodeInfo != null) {// 從節點信息中獲取文本CharSequence text = nodeInfo.getText();String eventText = text != null ? text.toString() : "";Log.i(TAG, "Clicked text: " + eventText);// 重要:記得回收nodeInfo對象nodeInfo.recycle();}break;}}

4 自動化UI Automator依靠 Accessibility API 實現

在 Android UI Automator 中主要依靠 Accessibility API 來實現。這個過程涉及到幾個關鍵的技術步驟,包括獲取根節點、遍歷節點、查詢節點屬性和執行操作。以下是這些步驟的具體實現細節和原理:

4.1 獲取根節點

首先,測試框架通過 AccessibilityService 獲取當前活動窗口的根 AccessibilityNodeInfo 對象。這是遍歷 UI 樹的起點。

在 Android 的 UI Automator 框架中,UiSelector 是一個強大的工具,用于創建針對特定 UI 元素的查詢。這些查詢可以基于多種屬性,如 ID、文本、內容描述、類名等。在底層,UI Automator 的 UiSelector 通過以下幾個步驟實現與 AccessibilityService 的交互和 UI 樹的遍歷:

a. 獲取 AccessibilityNodeInfo 根節點

首先,UI Automator 從輔助功能服務獲取當前活動窗口的根節點。

AccessibilityNodeInfo rootNode = UiAutomatorBridge.getInstance().getRootInActiveWindow();

這個方法調用返回的 rootNode 是當前顯示的窗口的頂層視圖節點。

b. 遍歷和匹配

然后,UiSelector 使用指定的條件(例如文本、類名等)對 AccessibilityNodeInfo 樹進行深度優先遍歷,查找符合條件的節點。

List<AccessibilityNodeInfo> matchNodes = rootNode.findAccessibilityNodeInfosByViewId("com.example:id/button_submit");

這個方法查找所有具有特定視圖 ID 的節點。類似的方法還有 findAccessibilityNodeInfosByTextfindAccessibilityNodeInfosByClassName,它們分別用于按文本和類名進行搜索。

c. 執行操作

一旦找到匹配的節點,UI Automator 可以在這些節點上執行各種操作,如點擊、輸入文本等。

for (AccessibilityNodeInfo node : matchNodes) {if (node.isClickable()) {node.performAction(AccessibilityNodeInfo.ACTION_CLICK);}
}

4.2 遞歸遍歷 UI 樹

UI Automator 使用遞歸方法遍歷整個 UI 樹,可以獲取或操作界面上的每一個元素。每個節點都代表屏幕上的一個 UI 元素,如按鈕、文本字段等。

底層代碼示例:
public void traverseTree(AccessibilityNodeInfo node) {if (node == null) return;// 處理當前節點,例如獲取節點的某些屬性int childCount = node.getChildCount();for (int i = 0; i < childCount; i++) {AccessibilityNodeInfo childNode = node.getChild(i);traverseTree(childNode);  // 遞歸調用以遍歷子節點childNode.recycle();  // 回收節點信息以避免內存泄漏}
}

此方法遍歷每個節點及其所有子節點,這是一種深度優先搜索(DFS)的遍歷方式。

4.3 查詢節點屬性

在遍歷的過程中,測試腳本可以查詢每個節點的各種屬性,例如文本內容、內容描述、類名等,以便識別需要操作的特定元素。

底層代碼示例:
String text = node.getText() != null ? node.getText().toString() : null;
String className = node.getClassName().toString();

4.4 執行用戶交互操作

UI Automator 允許執行各種用戶交互操作,如點擊、滑動等。這些操作是通過在相應的 AccessibilityNodeInfo 上調用操作方法實現的。

底層代碼示例:
if (node.getText() != null && node.getText().toString().equals("Click Me")) {node.performAction(AccessibilityNodeInfo.ACTION_CLICK);  // 執行點擊操作
}

4.5 使用選擇器

UI Automator 提供了強大的選擇器(UiSelector),允許測試腳本以聲明式方式查找 UI 元素。選擇器可以基于元素的各種屬性配置,如 ID、文本內容、類型等。

底層代碼示例:
UiObject button = new UiSelector().text("Submit").className("android.widget.Button").makeUiObject();
button.click();

UiSelector 允許測試腳本以非常靈活的方式指定元素的選擇條件。例如:

UiObject button = new UiObject(new UiSelector().className("android.widget.Button").text("Submit"));
button.click();

這段代碼創建了一個 UiSelector,用于查找文本為 “Submit” 的按鈕,并在找到后執行點擊操作。

5 AccessibilityNodeInfo樹的構建

當應用的 UI 發生變化時(例如用戶界面元素的添加、移動或更新),窗口管理系統將這些變化通知給輔助功能服務。
輔助功能服務使用這些信息來構建或更新一個輔助功能節點信息樹(即 AccessibilityNodeInfo 樹),這個信息樹反映了當前活動窗口的 UI 結構。
每個節點(AccessibilityNodeInfo)在樹中代表屏幕上的一個 UI 元素,例如按鈕、標簽、圖像等。
當調用 getRootInActiveWindow() 方法時,輔助功能服務從窗口管理系統查詢當前活動窗口的根節點。
這個根節點是 UI 樹的頂級節點,從這個節點開始,可以遍歷整個樹,訪問窗口中的所有 UI 元素。

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

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

相關文章

httprunner接口自動化測試框架使用說明【保姆級教程】

背景介紹&#xff1a; httprunner是國內開源的一個接口自動化框架&#xff0c;已經有部分公司開始使用這種框架來完成自己公司的接口自動化編寫&#xff0c;本文主要是從簡單的流程上去講解咋使用的&#xff08;PS&#xff1a;開發者本尊的官網教程寫的是真的爛。。。&#xf…

JVM調優實戰

如果老年代能回收掉大部分&#xff0c;說明年輕代太小了&#xff0c;放不下 OOM 1數據量一次性申請的內存過多&#xff0c;比如數據庫查詢返回值大多&#xff0c;所以做個分頁 2.并發過高的情況下&#xff0c;一些連接未釋放 3.堆內存不夠

DP-Kmaens密度峰值聚類算法

我有個問題 關于 [密度值>密度閾值] 的判定這里&#xff0c;新進來的新數據怎么確定他的密度值&#xff1f;密度閾值又是怎樣確定的呢&#xff1f;

正則表達式 0.1v

正則表達式 擴展 --> :% s/\///g //文件里面所有的 / 去掉 * 通配符 \ //轉義&#xff0c;讓字符變成原本的意思 ^ //行首 $ //行尾 [0-9] //數字 [a-z] //小寫字母 [A-Z] //大寫字母 把文件的小寫字母替換為大寫字母&#xff1f; 固定寫法 :% s/[a-…

Vscode git 插件

超好用的git記錄 軟件 安裝之后&#xff0c;鼠標在哪一行就可以看最新一次是誰提交的&#xff0c;真的超好用&#xff01;&#xff01;&#xff01;

43頁 | 2024年企業級BI平臺白皮書(免費下載)

【1】關注本公眾號&#xff0c;轉發當前文章到微信朋友圈 【2】私信發送 2024年企業級BI平臺白皮書 【3】獲取本方案PDF下載鏈接&#xff0c;直接下載即可。 誠摯邀請您微信掃碼加入以下方案驛站知識星球&#xff0c;獲取上萬份PPT/WORD解決方案&#xff01;&#xff01;&…

【NOI】C++程序結構入門之循環結構二-for循環

文章目錄 前言一、for循環1.導入2.語法3.使用場景4.條件控制5.小結 二、例題講解問題&#xff1a;1264 - 4位反序數問題&#xff1a;1085 - 尋找雷劈數問題&#xff1a;1057 - 能被5整除且至少有一位數字是5的所有整數的個數問題&#xff1a;1392 - 回文偶數&#xff1f;問題&a…

Linux命令 netstat -anp | grep 的用法

文章目錄 1、第一種解釋2、第二種解釋3、第三種解釋4、第四種解釋5、第五種解釋6、netstat --help 在Windows中&#xff0c;殺死端口占用的博客鏈接 1、第一種解釋 在Unix和Linux系統中&#xff0c;netstat -anp 命令用于顯示所有的網絡連接&#xff08; -a 表示所有&#xff…

文件md5加密

使用場景&#xff1a;為了避免上傳資源空間的浪費&#xff0c;通過對文件進行md5摘要加密獲取唯一的值&#xff0c;從數據庫中查詢是否已有該md5碼存在&#xff0c;不存在的就上傳&#xff0c;存在的話使用之前已存儲的文件信息。 如何加密 下載插件browser-md5-file 【之前有…

maridb10.4.30數據庫數據遷移

1.新建數據存儲文件夾&#xff0c;例如E:\maridb_data 2.修改原數據所在目錄的my.ini文件&#xff0c;例如D:\Program Files\MariaDB 10.4\data\my.ini 3.剪切除my.ini文件外的其他所有文件到遷移目的地文件(E:\maridb_data) 結果如下&#xff1a; 原數據文件目錄&#xff1a…

聊聊限流的一些事兒

一、背景 最近幾年&#xff0c;隨著微服務的流行&#xff0c;服務與服務之間依賴越來越強&#xff0c;調用也越來越復雜&#xff0c;服務間的穩定性變突顯出來。特別是在遇到突發請求時&#xff0c;常常需要通過緩存、限流、熔斷降級、負載均衡等多種方式保證服務的穩定性。其…

C++命名空間(詳解)

C基礎語法 C基于C語言的改進&#xff1a;c在C語言的基礎上引入并擴充了面向對象的概念 C基礎概念&#xff1a;C是基于C語言而產生的,它即可以進行C語言的過程化程序設計,又可以進行以抽象數據類型為特點的基于對象的程序設計,還可以進行面向對象的程序設計 在1998年 出現C98…

愛普生差分晶振在光模塊中的重要角色

光模塊是現代通信設備中的重要組成部分&#xff0c;主要用于實現光電轉換和信號傳輸&#xff0c;它是一種將光信號轉換為電信號&#xff0c;或者將電信號轉換為光信號的設備。在光纖通信中&#xff0c;光模塊扮演著至關重要的角色。 光模塊的主要組成部分包括光源、光接收器、…

OSPF學習筆記(狀態機)

1、鄰居關系 OSPF設備啟動后&#xff0c;會通過OSPF接口向外發送Hello報文&#xff0c;收到Hello報文的OSPF設備會檢查報文中所定義的參數&#xff0c;如果雙方一致就會形成鄰居關系&#xff0c;兩端設備互為鄰居 2、鄰接關系 形成鄰居關系后&#xff0c;如果兩端設備成功交…

【代碼隨想錄】【算法訓練營】【第27天】 [39]組合總和 [40] 組合總和II [131]分割回文串

前言 思路及算法思維&#xff0c;指路 代碼隨想錄。 題目來自 LeetCode。 day26&#xff0c; 休息的周末~ day 27&#xff0c;周一&#xff0c;庫存沒了&#xff0c;哭死~ 題目詳情 [39] 組合總和 題目描述 39 組合總和 解題思路 前提&#xff1a;組合的子集問題&…

C# :IQueryable IEnumerable

文章目錄 1. IEnumerable2. IQueryable3. LINQ to SQL4. IEnumerable & IQueryable4.1 Expression4.2 Provider 1. IEnumerable namespace System.Collections: public interface IEnumerable {public IEnumerator GetEnumerator (); }public interface IEnumerator {pubi…

氣泡式水位計施工技術要求

1、氣泡式水位計壓力氣管出氣口應安裝并固定在最低水位處&#xff0c;其壓力氣管也應固定&#xff0c;有條件的可用金屬管或塑料管保護。氣泡式水位計安裝示意圖見附圖。 2、安裝要求 1&#xff09;檢查氣泡式水位計氣管外觀有無破損及變形&#xff1b; 2&#xff09;旋開帶有…

面試數據庫八股文十問十答第十期

面試數據庫八股文十問十答第十期 作者&#xff1a;程序員小白條&#xff0c;個人博客 相信看了本文后&#xff0c;對你的面試是有一定幫助的&#xff01;關注專欄后就能收到持續更新&#xff01; ?點贊?收藏?不迷路&#xff01;? 1&#xff09;為什么不推薦多表Join&…

特征工程技巧—Bert

前段時間在參加比賽&#xff0c;發現有一些比賽上公開的代碼&#xff0c;其中的數據預處理步驟值得我們參考。 平常我們見到的都是數據預處理&#xff0c;現在我們來講一下特征工程跟數據預處理的區別。 數據預處理是指對原始數據進行清洗、轉換、縮放等操作&#xff0c;以便為…

Blackwell未來發展之路究竟如何?

英偉達Blackwell如何重塑AI計算的未來&#xff1f; 前言 臺灣大學演講 就在6月2日&#xff0c;英偉達CEO黃仁勛在中國臺灣大學綜合體育館發表了最新的演講。這次黃仁勛的演講依舊重磅&#xff0c;更值得注意的是這次演講中還透露了Blackwell今后的發展之路。 介紹Blackwell 介紹…