This article introduces the encapsulation of Flutter network requests and the presentation of different page states

Network request

The main use is dio library for network requests, the third library introduced. This is also possible with Flutter’s built-in HttpClient. Used to dio still can not put down. Or you can wrap HttpClient yourself if you are interested

The introduction of dio

Add to pubspec.yaml file

dio: ^3.010.
Copy the code

Introduce header file mode

import 'package:dio/dio.dart';
Copy the code

Simple packaging uses DIO

First, analyze the usage scenario. The common scenario is that after the user logs in and obtains the token, the user requests to obtain data in the request header. So let’s design along this line. Create a new base.dart file

import 'package:dio/dio.dart';

Dio initDio() {
  BaseOptions _baseOptions = BaseOptions(
      baseUrl: 'Set server address', connectTimeout: 15000);
  Dio dio = Dio(_baseOptions);
  dio.interceptors
      .add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
    print('Go network requested setup header');
    options.queryParameters['Authorization'] =
        SpUtil.getString('token', defValue: ' ');
    return options;
  }));
  return dio;
}
class Api {
  static Dio dio = initDio(a);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('Network request ended'); }}}Copy the code

This initializes DIO. Specific request we can create the file again. It’s a little messy together. For example, home page requests are put together, my page requests are put together. That should make sense

class ReqHome {
  Future<Map> loginInApi(username, password) {
    return Api.requestApi('post'.'/login',
        {"username": username, "password": password});
  }
  static Future<Map> getSwiperApi() {
    return Api.requestApi('get'.'address'{},); }}Copy the code

Here is the call, logged in as an example

Map result = await ReqHome().logininAPI (' username ', 'password '); Sputil. putString('token', 'token');Copy the code

After obtaining the token, you need to set the token in the header

 dio.interceptors
      .add(InterceptorsWrapper(onRequest: (RequestOptions options) async{// Add !!!!!! here options.queryParameters['Authorization'] =
        SpUtil.getString('token', defValue: ' ');
        
    return options;
  }));
Copy the code

Page different states display encapsulation

I used FutureBuilder to control the different states of the page. First create a class common_widget file, line analysis of a wave, page state divided into loading, loading completed empty data, loading completed display UI, loading failed. To demonstrate the successful loading of the image:Start by defining three properties

// final Future networkApi; // Final Function onSuccess; // Final Widget successWidget; // Successfully loaded viewCopy the code

Here is the main code:

@override
  Widget build(BuildContext context) {
    returnFutureBuilder<Map>(Future: widget.networkApi, Builder: (BuildContext Context, AsyncSnapshot snapshot) {// The request has endedif (snapshot.connectionState == ConnectionState.done) {
            print(snapshot);
            if(snapshot.haserror) {// Request failed, error displayedreturn _errorView;
            } else{// Request successful, data displayedif (snapshot.data == null || snapshot.data.length == 0) {
                return _emptyView;
              }
              widget.onSuccess();
              returnwidget.successWidget; }}else{// The request is not finished, loading is displayedreturnCenter( child: CircularProgressIndicator(), ); }}); }Copy the code

Calling code:

 @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('home'),
        ),
        body: CommonWidget(
          networkApi: ReqHome.getSwiperApi(),
          successWidget: successWidget(),
          onSuccess: () {},
        ));
  }
Copy the code

Displaying the wrong UI

Add code to the common_widget file:

/// error view 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("Loading failed. Please try again."),
          RaisedButton(
            color: Colors.red,
            onPressed: () {
              setState(() {});
            },
            child: Text(
              'reload',
              style: TextStyle(color: Colors.white),
            ),
          )
        ],
      ),
    );
  }
Copy the code

The effect is as follows:

Display empty data 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('No data at present'() [() [(); }Copy the code

Effect:

The e view can be modified according to the UI design, the answer structure is like this.

One more things…

  • List data refresh load encapsulation
  • Some tool class encapsulation