Flutter网络连接管理插件connection_manager的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter网络连接管理插件connection_manager的使用

标题

Flutter网络连接管理插件connection_manager的使用

内容

This package provides a simple implementation of a Connection Manager to do API request to a Server (REST or GraphQL). Furthermore, it provides an ApiCallBuilder widget to easily integrate API calls in the widget tree and a PaginatedApiCallBuilder widget to easily integrate paginated API calls in the widget tree.

Features

  • ConnectionManager: A class to make API requests, created setting a baseurl and headers to use for all the API calls.
  • PostApiResponse: A class to manage responses from the ConnectionManager, decoded by the provided class.
  • Decodable: A class to implement to let this package decode custom classes from a Map.
  • ApiCallBuilder: A widget to easily integrate API calls in the widget tree.
  • PaginatedApiCallBuilder: A widget to easily integrate paginated API calls in the widget tree.

Usage

Check the usage paragraph according to your needs.

Setting up

Before using the ConnectionManager, it must be initialized providing a baseUrl and headers. It can be useful to save a single instance of the ConnectionManager to be used all through the app, for example as a singleton.

To initialize the class:

ConnectionManager(
    baseUrl: "https://my-base-url.com",
    constantHeaders: {
        "Content-Type": "application/json",
    },
    decodeErrorFromMap: CustomError.fromMapError, // Optional, to let the package try to automatically decode errors from server. It's a method passed as a tear off
    mapStatusCodeFromResponse: (map) => map?["code"], // Optional, you can use this method to map a code from body and use it to override the http status code.
    onTokenExpiredRuleOverride: (response) {
      if (response.statusCode == 500 && response.body.contains("missing auth")) {
        return true;
      }
      return false;
    }, /// Optional, this method can be used in combination with `onTokenExpired` to define a custom rule to trigger the `onTokenExpired` method. By default, `onTokenExpired` is fired when the http response has a 401 status code. Eventually, this rule can be expanded thanks to this method.
    onTokenExpired: () async {
      return await refreshToken(); // refreshToken is not a method of this package
    }, // A function fired when the http client gives a 401 response after an API call. It is used to refresh the auth token, if set, and after returning the new token the [ConnectionManager] will attempt the API call once again.
    onResponseReceived: (Response response) {
      print(response.body);
    },  // A function fired, if not _null_, when the `doApiRequest` method receives a response from the BE. This can be useful to manage broadly a `Response` the same way for every api call.
    returnCatchedErrorMessage: true, // Specify if the error message coming from the try-catch block in `doApiRequest` should be returned in the response (i.e. decoding errors). Default to _true_.
    duration: const Duration(seconds: 1), // Specify the timeout for all the API calls done with this [ConnectionManager]. Defaults to 1 minute.
    persistCookies: false, // If _true_, creates a persistent instance of a cookie manager to be used for all the API calls done with this [ConnectionManager]. Defaults to _false_
    client: Client(), // If set, overrides the default http client for API calls
)

In the example above, CustomError is a local class that implements Decodable in this package and its fromMapError method. See Decodable documentation for further details.

You can store a single instance of the ConnectionManager as a Provider or as a singleton. Check this example:

class NetworkProvider {
  final String baseUrl;

  // Connection Manager definition
  final _connectionManager = ConnectionManager<CustomError>(
      baseUrl: baseUrl,
      constantHeaders: {"Content-Type": "application/json"},
      decodeErrorFromMap: CustomError.fromMapError,
      onTokenExpired: () async {
        return await refreshToken(); // refreshToken() is not a method of this package
      },
      onResponseReceived: (Response response) {
        print(response.body);
      },
      returnCatchedErrorMessage: true,
   );

  // Connection Manager getter
  ConnectionManager<CustomError> get connectionManager => _connectionManager;
 }

 // Use the provider
 class MyApp extends StatelessWidget {
   @override build(BuildContext context) {
     return Provider(
       create: (context) => NetworkProvider(
         baseUrl: "https://test.com/api",
       ),
       child: Builder(
         builder: (context) {
           var networkProvider = context.read<NetworkProvider>();
           return Text(networkProvider.baseUrl);
         }
       ),
     );
   }
 }

Modify ConnectionManager

Other than passing constant headers to the ConnectionManager constructor, it is possible to add/remove extra headers to be used for all the API calls by calling one of the following methods on the created instance.

context.read<NetworkProvider>().connectionManager.setSharedHeaders({
  "Authorization" : "token"
});

context.read<NetworkProvider>().connectionManager.setAuthHeader("Bearer token");

context.read<NetworkProvider>().connectionManager.removeAuthHeader();

Furthermore, it is possibile to edit the baseurl

context.read<NetworkProvider>().connectionManager.changeBaseUrl("https://test.com/api/v1");

Make an api request

To make an API request simply call the method doAPIRequest on the ConnectionManager, passing all the required parameters, and eventually other headers or a body.

The method is asyncronous, and it will return a PostApiResponse as a Future, containing the decoded content, the http status code and eventually an error message.

Other than specifying the request type (get, post…), it is possible to specify the body type: json, formdata, graphQL… To do so, use the bodyType parameter (defaults to json type). Note: When passing a json body, it’s mandatory to json encode the Map, as follows.

var response = await context.read<NetworkProvider>().connectionManager.doApiRequest(
  requestType: ApiRequestType.post,
  endpoint: "/test-endpoint",
  body: jsonEncode({
    "test": "test"
  }),
);

When using a formData body, it’s mandatory to pass it as a Map<String,dynamic>. To pass a file, use the FileData class provided by this library to create a file and add it as a vaue of the Map. It’s left to the package to manage it correctly.

Whenn using a graphQL body, it’s mandatory to pass it as a [String]. Parameters must be passed as values in the string itself. The [ApiRequestType] should be get for queries or anything else for mutations.


更多关于Flutter网络连接管理插件connection_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter网络连接管理插件connection_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用Flutter中的connection_manager插件进行网络连接管理的代码示例。connection_manager插件允许你检测设备的网络连接状态,并在连接状态发生变化时执行相应的操作。

首先,你需要在你的pubspec.yaml文件中添加connection_manager依赖:

dependencies:
  flutter:
    sdk: flutter
  connection_manager: ^0.6.0  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

接下来是一个完整的Flutter应用示例,它展示了如何使用connection_manager插件来监听网络连接状态的变化:

import 'package:flutter/material.dart';
import 'package:connection_manager/connection_manager.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  ConnectionManager _connectionManager = ConnectionManager();
  String _connectionStatus = "Checking...";

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _checkConnectionStatus();
    _connectionManager.status.listen((status) {
      setState(() {
        _updateConnectionStatus(status);
      });
    });
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    _connectionManager.dispose();
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      _checkConnectionStatus();
    }
  }

  Future<void> _checkConnectionStatus() async {
    var status = await _connectionManager.checkConnection();
    _updateConnectionStatus(status);
  }

  void _updateConnectionStatus(ConnectionStatus status) {
    setState(() {
      switch (status) {
        case ConnectionStatus.WIFI:
          _connectionStatus = "Connected to Wi-Fi";
          break;
        case ConnectionStatus.MOBILE:
          _connectionStatus = "Connected to Mobile Data";
          break;
        case ConnectionStatus.NONE:
          _connectionStatus = "No Internet Connection";
          break;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Connection Manager Example'),
        ),
        body: Center(
          child: Text(
            _connectionStatus,
            style: TextStyle(fontSize: 24),
          ),
        ),
      ),
    );
  }
}

代码说明:

  1. 依赖添加:在pubspec.yaml中添加connection_manager依赖。
  2. 状态管理:使用StatefulWidgetState来管理应用的状态。
  3. 初始化:在initState方法中初始化ConnectionManager实例,并添加监听器来监听连接状态的变化。
  4. 连接状态检查:定义一个_checkConnectionStatus方法,用于检查当前的连接状态。
  5. 更新UI:根据连接状态更新UI文本。
  6. 生命周期管理:在didChangeAppLifecycleState方法中,当应用从后台切换到前台时,重新检查连接状态。
  7. 资源释放:在dispose方法中释放资源,避免内存泄漏。

这个示例展示了如何使用connection_manager插件来检测设备的网络连接状态,并在状态变化时更新UI。你可以根据实际需求进一步扩展这个示例。

回到顶部