前言
App 的大部分頁面都會涉及到數(shù)據(jù)加載催什、錯誤宰睡、無數(shù)據(jù)和正常幾個狀態(tài),在一開始的時候我們可能數(shù)據(jù)獲取的狀態(tài)枚舉用 if...else
或者 switch
來顯示不同的 Widget
旋圆,這種方式會顯得代碼很丑陋麸恍,譬如下面這樣的代碼:
if (PersonalController.to.loadingStatus == LoadingStatus.loading) {
return Center(
child: Text('加載中...'),
);
}
if (PersonalController.to.loadingStatus == LoadingStatus.failed) {
return Center(
child: Text('請求失敗'),
);
}
// 正常狀態(tài)
PersonalEntity personalProfile = PersonalController.to.personalProfile;
return Stack(
...
);
這種情況實在是不夠優(yōu)雅,在 GetX 中提供了一種 StateMixin
的方式來解決這個問題孩等。
StateMixin
StateMixin
是 GetX 定義的一個 mixin
采够,可以在狀態(tài)數(shù)據(jù)中混入頁面數(shù)據(jù)加載狀態(tài)蹬癌,包括了如下狀態(tài):
-
RxStatus.loading()
:加載中; -
RxStatus.success()
:加載成功逝薪; -
RxStatus.error([String? message])
:加載失敗,可以攜帶一個錯誤信息message
董济; -
RxStatus.empty()
:無數(shù)據(jù)虏肾。
StateMixin 的用法如下:
class XXXController extends GetxController
with StateMixin<T> {
}
其中 T 為實際的狀態(tài)類控漠,比如我們之前一篇 PersonalEntity,可以定義為:
class PersonalMixinController extends GetxController
with StateMixin<PersonalEntity> {
}
然后StateMixin
提供了一個 change
方法用于傳遞狀態(tài)數(shù)據(jù)和狀態(tài)給頁面。
void change(T? newState, {RxStatus? status})
其中 newState
是新的狀態(tài)數(shù)據(jù)脑融,status
就是上面我們說的4種狀態(tài)缘琅。這個方法會通知 Widget
刷新。
GetView
GetX 提供了一個快捷的 Widget
用來訪問容器中的 controller
驯杜,即 GetView
做个。GetView
是一個繼承 StatelessWidget
的抽象類,實現(xiàn)很簡單顽频,只是定義了一個獲取 controller
的 get
屬性太闺。
abstract class GetView<T> extends StatelessWidget {
const GetView({Key? key}) : super(key: key);
final String? tag = null;
T get controller => GetInstance().find<T>(tag: tag)!;
@override
Widget build(BuildContext context);
}
通過繼承 GetView
,就可以直接使用controller.obx
構(gòu)建界面蟀淮,而 controller.obx
最大的特點是針對 RxStatus
的4個狀態(tài)分別定義了四個屬性:
Widget obx(
NotifierBuilder<T?> widget, {
Widget Function(String? error)? onError,
Widget? onLoading,
Widget? onEmpty,
})
- NotifierBuilder<T?> widget:實際就是一個攜帶狀態(tài)變量,返回正常狀態(tài)界面的函數(shù)涨缚,NotifierBuilder<T?>的定義如下策治。通過這個方法可以使用狀態(tài)變量構(gòu)建正常界面。
typedef NotifierBuilder<T> = Widget Function(T state);
-
onError
:錯誤時對應(yīng)的Widget
構(gòu)建函數(shù)茂翔,可以使用錯誤信息error
履腋。 -
onLoading
:加載時對應(yīng)的Widget
; -
onEmpty
:數(shù)據(jù)為空時的Widget
俐末。
通過這種方式可以自動根據(jù) change
方法指定的 RxStatus
來構(gòu)建不同狀態(tài)的 UI 界面奄侠,從而避免了丑陋的 if...else
或 switch
語句。例如我們的個人主頁烹卒,可以按下面的方式來寫弯洗,是不是感覺更清晰和清爽了?
class PersonalHomePageMixin extends GetView<PersonalMixinController> {
PersonalHomePageMixin({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return controller.obx(
(personalEntity) => _PersonalHomePage(personalProfile: personalEntity!),
onLoading: Center(
child: CircularProgressIndicator(),
),
onError: (error) => Center(
child: Text(error!),
),
onEmpty: Center(
child: Text('暫無數(shù)據(jù)'),
),
);
}
}
對應(yīng)的PersonalMixinController的代碼如下:
class PersonalMixinController extends GetxController
with StateMixin<PersonalEntity> {
final String userId;
PersonalMixinController({required this.userId});
@override
void onReady() {
getPersonalProfile(userId);
super.onReady();
}
void getPersonalProfile(String userId) async {
change(null, status: RxStatus.loading());
var personalProfile = await JuejinService().getPersonalProfile(userId);
if (personalProfile != null) {
change(personalProfile, status: RxStatus.success());
} else {
change(null, status: RxStatus.error('獲取個人信息失敗'));
}
}
}
Controller 的構(gòu)建
從 GetView 的源碼可以看到,Controller 是從容器中獲取的逃贝,這就需要使用 GetX 的容器沐扳,在使用 Controller 前注冊到 GetX 容器中。
Get.lazyPut<PersonalMixinController>(
() => PersonalMixinController(userId: '70787819648695'),
);
總結(jié)
本篇介紹了使用GetX
的 StateMixin
方式構(gòu)建更優(yōu)雅的頁面結(jié)構(gòu)躯嫉,通過controller.obx
的參數(shù)配置不同狀態(tài)對應(yīng)不同的組件∑聿停可以根據(jù) RxStatus
狀態(tài)自動切換組件帆阳,而無需寫丑陋的 if...else
或 switch
語句。當然舱痘,使用這種方式的前提是需要在 GetX
的容器中構(gòu)建 controller
對象芭逝,本篇源碼已上傳至:GetX 狀態(tài)管理源碼渊胸。實際上使用容器能夠帶來其他的好處,典型的應(yīng)用就是依賴注入(Dependency Injection胖翰,簡稱DI)切厘,接下來我們會使用兩篇來介紹依賴注入的概念和具體應(yīng)用。