## 1. GetConnect

GetConnect是可以使用HTTP或WebSocks使前台与后台的通信,同时能保证数据出现错误时,不会出现App闪退

演示接口地址

代码仓库

1.1 如何使用

第一步:创建模型model

json转dart网址

  1. class MakeupModel {
  2. // 略了
  3. }

第二步:创建 provider 集成自 GetConnect

  1. const String APIADDRESS =
  2. 'https://makeup-api.herokuapp.com/api/v1/products.json/';
  3. class HomeProvider extends GetConnect {
  4. @override
  5. void onInit() {
  6. // 这个是json转model的, 可以这么写
  7. // httpClient.defaultDecoder = (json) => MakeupModel.fromJson(json);
  8. // 也可以这么写
  9. httpClient.defaultDecoder = MakeupModel.fromJson;
  10. // 创建公共接口地址
  11. httpClient.baseUrl = APIADDRESS;
  12. }
  13. // 获取接口数据源
  14. Future<Response<List<MakeupModel>>> getMakeupModel() async =>
  15. await get('?brand=maybelline');
  16. }
  17. // 多个接口的话,可以在抽离出来一层,毕竟接口地址 和 请求拦截,响应拦截等都是固定的
  18. class BaseConnect extends GetConnect {
  19. @override
  20. void onInit() {
  21. // 创建公共接口地址
  22. httpClient.baseUrl = APIADDRESS;
  23. // 请求拦截
  24. httpClient.addRequestModifier((request) {
  25. request.headers["token"] = "token";
  26. return request;
  27. });
  28. // 响应拦截
  29. httpClient.addResponseModifier((request, response) {
  30. // 处理逻辑
  31. return response;
  32. });
  33. }
  34. }
  35. class HomeProvider extends BaseConnect {
  36. @override
  37. void onInit() {
  38. // 某个接口的json-to-model
  39. httpClient.defaultDecoder = MakeupModel.fromJson;
  40. super.onInit();
  41. }
  42. Future<Response<List<MakeupModel>>> getMakeupModel() async =>
  43. await get('?brand=maybelline');
  44. }

第三步:创建 controller 集成自 GetxController 混入 StateMixin

  1. /// 创建controller
  2. class HomeController extends GetxController with StateMixin<List<MakeupModel>> {
  3. // 获取实例
  4. final provider = Get.find<HomeProvider>();
  5. @override
  6. void onInit() {
  7. // 调用
  8. fetchList();
  9. super.onInit();
  10. }
  11. // 处理接口返回的数据
  12. Future<void> fetchList() async {
  13. // 获取数据
  14. final Response res = await provider.getMakeupModel();
  15. // 判断,如果有错误
  16. if (res.hasError) {
  17. // 改变数据,传入错误状态,在ui中会处理这些错误
  18. change(null, status: RxStatus.error(res.statusText));
  19. } else {
  20. // 否则,存储数据,改变状态为成功
  21. change(res.body, status: RxStatus.success());
  22. }
  23. }
  24. }

第四步:创建 binding 实现 Bindings类

  1. class HomeBinding implements Bindings {
  2. @override
  3. void dependencies() {
  4. Get.lazyPut<HomeController>(() => HomeController());
  5. Get.lazyPut<HomeProvider>(() => HomeProvider());
  6. }
  7. }

第五步: 连接UI渲染数据

渲染时,需要使用 controller.obx() 拿到接口中的数据

传入参数 说明
(state) => Widget 传入函数,参数是接口返回的数据,返回值是要渲染的组件
onEmpty 传入一个组件,在数据为空时展示
onLoading 传入一个组件,在数据加载时显示的loading
onError (String) => Widget,发生错误时渲染
  1. class Home extends GetView<HomeController> {
  2. const Home({Key key}) : super(key: key);
  3. @override
  4. Widget build(BuildContext context) {
  5. return Scaffold(
  6. appBar: AppBar(
  7. title: Text('Make up'),
  8. ),
  9. body: controller.obx(
  10. (state) => ListView.separated(
  11. itemCount: state.length,
  12. itemBuilder: (context, index) {
  13. final MakeupModel makeUp = state[index];
  14. return ListTile(
  15. onTap: () => null,
  16. title: Text(makeUp.name),
  17. trailing: Text("\$${makeUp.price}"),
  18. leading: MakeUpImage(makeUp: makeUp),
  19. );
  20. },
  21. ),
  22. onError: (err) {
  23. return Text("$err");
  24. },
  25. // 自定义loading和文字,不传的话,默认只有一个loading,没有文字
  26. onLoading: Container(
  27. width: double.infinity,
  28. height: double.infinity,
  29. child: Column(
  30. mainAxisAlignment: MainAxisAlignment.center,
  31. crossAxisAlignment: CrossAxisAlignment.center,
  32. children: [
  33. CircularProgressIndicator(),
  34. SizedBox(height: 10),
  35. Text(
  36. "疯狂加载中...",
  37. style: TextStyle(color: Colors.blue, fontSize: 16),
  38. ),
  39. ],
  40. ),
  41. ),
  42. ),
  43. );
  44. }
  45. }