深入瞭解 GetX 的 Obx 與 Rx

更新於 2024/12/18閱讀時間約 7 分鐘


最近在做畫面時,滿常使用 GetX 的 Obx + Rx 變數,讓畫面可以根據狀態變化即時更新。過程中有時會碰到一些錯誤,在建置 Widget 的過程中,因為 Obx 找不到可以被監聽的目標,導致 Obx 認為使用者錯誤的使用了 Obx,所以透過 Exception 來提醒使用者。

raw-image

Obx 的使用方法是把一個 builder 方法傳給 Obx 這個 Widget,不需要任何 Rx 變數做為參數。像是下面的這個簡單的 count 例子中,Obx 傳入一個 builder 方法,只要 builder 在建置 Widget 的過程中使用 Rx 變數,Obx 就能進行監聽。

raw-image

這就讓我自己十分好奇,Obx 到底是如何找到 builder 方法中的 Rx 變數,然後對這個 Rx 變數進行監聽呢?自己花了一些時間研究和實驗,今天就來分享一下,到底 GetX 中的 Obx 是如何完成他的工作的。

兩位主角

在 Counter 例子中,有兩個重要的物件,一個是 Obx,另一個則是存放 count 的 Rx 變數。其中 Obx 身上有一個型態為 RxNotifier 的 _observer 變數,主要用來監聽 Rx 變數並更新畫面的。而存放 count 的 Rx 變數的爺爺也是 RxNotifier。

raw-image

RxNotifier 本身沒有任何實作,實作都是集中 NotifyManager 這個 mixin 身上。NotifyManger 身上主要有兩個方法

  1. addListener:用來決定監聽什麼事件
  2. listen:用來決定監聽到事件後,要做什麼事

Obx 如何更新畫面

當開始 build GetCountView 的畫面並 build 到 Obx 時,程式會先執行 ObxWidget initState() 方法。在 initState() 中執行 _observer.listen,並傳入 _updateTree,讓 _observer 監聽到事件時,可以呼叫 setState 更新畫面。

raw-image

再來程式會走進 ObxWidget 的 build 方法。可以發現 ObxWidget 的 build 方法也就只是轉頭呼叫 RxInterface 的 notifyChildren 靜態方法,並傳入 ObxWidget 身上的 _observer 和 widget.build

raw-image

此時的 widget.build 也就是我們在 GetCountView 中傳給 Obx 的那段印出 count 的 builder。

raw-image

當我們在深入 RxInterface.notifyChildren 之後,可以發現在程式會把 ObxWidget 身上的 _observer 塞到一個全域變數 RxInterface.proxy 中。然後繼續執行 builder 並 build 出顯示 count 數的 Text Widget。最後把 RxInterface.proxy 還原成原本的值,然後就回傳結果了。

raw-image

看到這邊好像還是不知道 Obx 到底是如何發現 builder 之中的 RxInt 的,我們只有看到 _observer 被賦予了他要觸發 setState 的工作,但是 _observer 是如何監聽 count 事件呢?

在 Getter 中註冊監聽

其實關鍵就在 builder 中。我們回頭看一下使用 Obx 那段程式碼,Text 中使用了 count.value,而關鍵就在這個 value getter 中。

raw-image

讓我們深入看一下 value 這個 getter 是如何被實作的。

raw-image

在使用 value getter 時,程式會向 RxInterface.proxy 這個全域變數註冊一個 subject,還記得先前 RxInterface.notifyChildren 做了什麼嗎,它把 ObxWidget 身上的 _observer 塞給 RxInterface.proxy,此時 value getter 中用的對象就是 ObxWidget 身上的 _observer。最後,當 value 發生變化時, Rx 變數就會透過 subject 通知 _observer。

簡單來說,Obx 與 Rx 變數是透過 RxInterface 這個全域變數作為橋樑,讓兩者可以在 build 的時候建立觀察者模式。當 Rx 變數透過 value setter 賦值時,就能成功通知 ObxWidget 身上的 _observer,_observer 接收到事件之後就觸發 setState(),讓畫面根據新的狀態更新。

整理流程

  1. GetCounterView 開始建置,隨後呼叫 ObxWidget 的 build 方法
  2. ObxWidget 的 build 方法被呼叫後,轉頭直接把工作轉交給 RxInterface.notifyChildren,並且傳入 _observer 與 builder
  3. RxInterface 先是把 _observer 放進 RxInterface.proxy 中
  4. RxInterface.notifyChildren 呼叫 builder,建置 builder 中的 Widget
  5. builder 在建置的過程中會使用 count 這個 Rx 變數取得 count 值
  6. 取得 count 值過程中,Rx 也會呼叫 RxInterface.proxy?.addListener,讓 _observer 可以監聽

raw-image

ps. 實際上並不是由 GetCountView 直接呼叫 ObxWidget.build 的,這邊只是簡化一下呼叫流程。實際上是由 GetCountView 的 Element 去呼叫的。

小結

GetX 作為熱門的 Flutter 狀態管理套件之一,有許多容易使用的 API,其中也大量的使用全域變數 。使用的時候還需要多加考慮一下,用得太多容易導致產品程式碼與套件緊緊相依,不只測試難寫,想抽換狀態管理的套件也會十分麻煩,使用的時候需要多多思考。

分享各種軟體開發技巧與心得
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
本系列文章聚焦 Flutter 開發中常見問題,如畫面開發、狀態管理與 API 呼叫,結合 SOLID 等設計原則,提供實用解法與優缺點分析,幫助讀者選擇合適方法。透過 DartPad 範例,讀者可實際執行、修改程式碼,加深理解設計理念,提升開發效率與程式碼品質。
這篇文章說明在 Flutter App 中整合 Google Play 內購功能的流程。主要包含兩個部分:先在 Google Play Console 設定商品,然後使用 Flutter 的 in_app_purchase 套件實作購買功能。開發時需注意連線狀態、商品列表獲取,以及購買流程的實作。
本系列文章聚焦 Flutter 開發中常見問題,如畫面開發、狀態管理與 API 呼叫,結合 SOLID 等設計原則,提供實用解法與優缺點分析,幫助讀者選擇合適方法。透過 DartPad 範例,讀者可實際執行、修改程式碼,加深理解設計理念,提升開發效率與程式碼品質。
這篇文章說明在 Flutter App 中整合 Google Play 內購功能的流程。主要包含兩個部分:先在 Google Play Console 設定商品,然後使用 Flutter 的 in_app_purchase 套件實作購買功能。開發時需注意連線狀態、商品列表獲取,以及購買流程的實作。
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
就是指變數可以被訪問和使用的範圍,來說一下var、let和const的作用域差異。 var :function example() { console.log(x); // 輸出: undefined 因為變量提升造成的 var x = 5; } 函數作用域或全域作用域 可以重複宣告
Thumbnail
本文介紹了在網站開發中如何運用狀態機的原則和設計方法。通過具體案例分析,以及狀態和數據的區分,詳細介紹了狀態機的設計原則和應用。讀者可以通過本文瞭解如何將狀態機應用於實際的網站開發中。
Thumbnail
在網路速度有限的情況下,依序記錄不斷產生的資訊,能統計使用者在頁面上操作了哪些功能。
Thumbnail
瞭解如何在Xcode15及以上使用Logger進行更好的程式debug。Logger可以更好的組織Log,但也有一些缺點需要注意。本文將介紹Logger的基本使用方式,以及一些注意事項。
※ 觀察者模式 定義: 觀察者模式(Observer Pattern)是一種設計模式,涉及兩個主要角色:觀察者(Observers)和被觀察者(Subject)。在這種模式中,一群觀察者訂閱並觀察某個被觀察的對象。當被觀察者的狀態發生改變時,它會通知所有觀察者,讓他們知曉並作出相應的反應。這種模
Thumbnail
需求情境: 在設計畫面時,資料來源是後台的 api,每一次畫面細節的修修改改,都會觸發 Xcode Preview 程序,導致不斷呼叫後台。此時若資料結構和大小都具有一定規模,就會導致效率低落,不斷等待,且消耗伺服器資源甚鉅。 解決方案: 將後台傳回的資料以檔案形式暫存在本地端,每次 pr
setter和getter能把狀態改變時需做的事情包裝起來,讓外部只需簡單修改參數就能達到預想的效果
Thumbnail
當你在開發程式時,難免會遇到各種錯誤和異常情況。這些錯誤可能是因為代碼中的錯誤、外部資源無法訪問或其他不可預期的狀況。為了提高程式的可靠性、穩定性和可維護性,我們使用「例外處理」來處理這些異常情況。
Thumbnail
Request內容 package main import ( "fmt" "log" "net/http" "strings" ) func request(w http.ResponseWriter, r *http.Request) { //這些資訊是輸出到伺服器端的列印訊息
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
就是指變數可以被訪問和使用的範圍,來說一下var、let和const的作用域差異。 var :function example() { console.log(x); // 輸出: undefined 因為變量提升造成的 var x = 5; } 函數作用域或全域作用域 可以重複宣告
Thumbnail
本文介紹了在網站開發中如何運用狀態機的原則和設計方法。通過具體案例分析,以及狀態和數據的區分,詳細介紹了狀態機的設計原則和應用。讀者可以通過本文瞭解如何將狀態機應用於實際的網站開發中。
Thumbnail
在網路速度有限的情況下,依序記錄不斷產生的資訊,能統計使用者在頁面上操作了哪些功能。
Thumbnail
瞭解如何在Xcode15及以上使用Logger進行更好的程式debug。Logger可以更好的組織Log,但也有一些缺點需要注意。本文將介紹Logger的基本使用方式,以及一些注意事項。
※ 觀察者模式 定義: 觀察者模式(Observer Pattern)是一種設計模式,涉及兩個主要角色:觀察者(Observers)和被觀察者(Subject)。在這種模式中,一群觀察者訂閱並觀察某個被觀察的對象。當被觀察者的狀態發生改變時,它會通知所有觀察者,讓他們知曉並作出相應的反應。這種模
Thumbnail
需求情境: 在設計畫面時,資料來源是後台的 api,每一次畫面細節的修修改改,都會觸發 Xcode Preview 程序,導致不斷呼叫後台。此時若資料結構和大小都具有一定規模,就會導致效率低落,不斷等待,且消耗伺服器資源甚鉅。 解決方案: 將後台傳回的資料以檔案形式暫存在本地端,每次 pr
setter和getter能把狀態改變時需做的事情包裝起來,讓外部只需簡單修改參數就能達到預想的效果
Thumbnail
當你在開發程式時,難免會遇到各種錯誤和異常情況。這些錯誤可能是因為代碼中的錯誤、外部資源無法訪問或其他不可預期的狀況。為了提高程式的可靠性、穩定性和可維護性,我們使用「例外處理」來處理這些異常情況。
Thumbnail
Request內容 package main import ( "fmt" "log" "net/http" "strings" ) func request(w http.ResponseWriter, r *http.Request) { //這些資訊是輸出到伺服器端的列印訊息