接上文,這篇文章主要介紹Flutter網路請求, 頁面不同狀態展示的封裝
網路請求
主要使用的是dio庫進行網路請求,引入的第三個庫。對於Flutter的自帶的HttpClient也可以。用習慣了dio還是放不下。或者有興趣的可以自己對於HttpClient封裝一下
引入dio
在pubspec.yaml檔案中加入
dio: ^3.0.10
複製程式碼
引入標頭檔案方式
import 'package:dio/dio.dart';
複製程式碼
簡單封裝使用dio
先分析一下使用場景,比較常見的場景是使用者登入之後獲取到token之後,設定在請求頭中進行請求獲取資料。接下來沿著這個思路設計一下。 新建一個base.dart檔案
import 'package:dio/dio.dart';
Dio initDio() {
BaseOptions _baseOptions = BaseOptions(
baseUrl: '設定伺服器地址', connectTimeout: 15000);
Dio dio = Dio(_baseOptions);
dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
print('走網路請求了設定頭部了');
options.queryParameters['Authorization'] =
SpUtil.getString('token', defValue: '');
return options;
}));
return dio;
}
class Api {
static Dio dio = initDio();
static Future<Map> requestApi(method, path, data) async {
Response result;
try {
if (method == 'get') {
result = await dio.get(path, queryParameters: data);
} else if (method == 'post') {
result = await dio.post(path, data: data);
}
print(result);
return result.data;
} on DioError catch (e) {
print(e);
if (e == null) {
return Future.error(Response(data: -1));
} else if (e.response != null) {
if (e.response.statusCode >= 300 && e.response.statusCode < 400) {
return Future.error(Response(data: -1));
} else {
result = e.response;
return Future.value(result.data);
}
} else {
return Future.error(Response(data: -1));
}
} finally {
print('網路請求結束');
}
}
}
複製程式碼
以上初始化了dio。具體的請求我們可以再建立檔案。放在一起比較亂。比如首頁的請求放在一起,我的頁面的請求放在一起。應該能理解哈
class ReqHome {
Future<Map> loginInApi(username, password) {
return Api.requestApi('post', '/login',
{"username": username, "password": password});
}
static Future<Map> getSwiperApi() {
return Api.requestApi('get', '地址', {});
}
}
複製程式碼
下面就是呼叫了,已登入為例
Map result = await ReqHome().loginInApi('使用者名稱', '密碼');
// 這樣在獲取到token之後在存入到本地
SpUtil.putString('token', '獲取的token');
複製程式碼
獲取到token之後需要把token設定在header中
dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
// 在這新增!!!!!!
options.queryParameters['Authorization'] =
SpUtil.getString('token', defValue: '');
return options;
}));
複製程式碼
頁面不同狀態展示封裝
我是用FutureBuilder來控制頁面顯示不同狀態。首先建立個類common_widget檔案, 線分析一波,頁面狀態分成載入中, 載入完成空資料, 載入完成展示UI,載入失敗。 演示一下載入成功的圖視: 首先定義三個屬性
// final Future networkApi; // 傳進來的網路請求
// final Function onSuccess; // 載入成功之後把資料傳遞出去
// final Widget successWidget; // 載入成功的檢視
複製程式碼
下面是主要程式碼:
@override
Widget build(BuildContext context) {
return FutureBuilder<Map>(
future:
widget.networkApi,
builder: (BuildContext context, AsyncSnapshot snapshot) {
// 請求已結束
if (snapshot.connectionState == ConnectionState.done) {
print(snapshot);
if (snapshot.hasError) {
// 請求失敗,顯示錯誤
return _errorView;
} else {
// 請求成功,顯示資料
if (snapshot.data == null || snapshot.data.length == 0) {
return _emptyView;
}
widget.onSuccess();
return widget.successWidget;
}
} else {
// 請求未結束,顯示loading
return Center(
child: CircularProgressIndicator(),
);
}
});
}
複製程式碼
呼叫程式碼:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('首頁'),
),
body: CommonWidget(
networkApi: ReqHome.getSwiperApi(),
successWidget: successWidget(),
onSuccess: () {},
));
}
複製程式碼
展示錯誤UI
在common_widget檔案中加入程式碼:
///錯誤檢視
Widget get _errorView {
return Container(
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// Image.asset(
// 'assets/images/load_error_view.png',
// height: 80,
// width: 100,
// ),
Text("載入失敗,請重試"),
RaisedButton(
color: Colors.red,
onPressed: () {
setState(() {});
},
child: Text(
'重新載入',
style: TextStyle(color: Colors.white),
),
)
],
),
);
}
複製程式碼
效果如下:
展示空資料UI
///資料為空的檢視
Widget get _emptyView {
return Container(
width: double.infinity,
height: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 10),
child: Text('暫無資料'),
)
],
),
);
}
複製程式碼
效果圖:
檢視可以根據UI設計去修改,答題結構就是這樣子的。。
one more things。。。。。。
- 列表資料重新整理載入封裝
- 一些工具類封裝