为什么我的 flutter http 网络调用很慢?

Pea*_*Gen 8 android http ios dart flutter

我正在开发一个具有网络活动的颤振应用程序。为了获取数据,我连接到一个REST API,这个 API 的速度很快。

有关更多信息,此 API 正在使用AWS API GatewayAWS Lambda与其他 AWS 技术一起使用。

下面是我的代码,连接到网络。

class RoleService with ChangeNotifier {
  NavLinks _navLinks = NavLinks();
  late List<Role> _roles;



  /// Get all Roles
  Future<void> getAllRoles(String authToken) async {
    try {
      var data = await http.get(
        Uri.parse("https://api2.example.com/userrel/roles/getall"),
        headers: {HttpHeaders.authorizationHeader: "Bearer $authToken"},
      );
      var jsonData =
          convert.json.decode(data.body).cast<Map<String, dynamic>>();
      _roles = jsonData.map<Role>((json) => new Role.fromJson(json)).toList();
      print(_roles);
    } catch (error) {
      print(error);
      throw error;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以在下面看到postman上述API调用的性能。对于颤振测试,我使用华为 p30 Lite Android 手机。

在此输入图像描述

然后,当我API在 flutter 中执行相同的调用时,这就是我得到的。

在此输入图像描述

观察输出,postman我可以看到它缓存了 DNS 查找、TCP 握手和 SSL 握手。postman 在第一次调用 API 基本 URI 后执行此操作。然后从第二次开始,DNS 查找等会被缓存,从而在将来对同一基本 URI 的 API 调用中节省大量时间。

但在颤振中,“连接建立”时间很长,即使检索数据的时间只有几毫秒。

如何避免连接延迟并获得最大性能?如果缓存 SSL、DNS 查找等是解决方案,我该如何在 flutter 中做到这一点?

Pea*_*Gen 12

看来这个问题很多人都有。那么,让我回答我自己的问题。

flutter 能记住网络连接吗?是的,它可以。

Flutter 只需要对同一 API 进行一次网络调用即可记住连接。从第二次调用相同的 API 开始,它将使用其“缓存”内存,为您带来巨大的性能提升。

所以首先请记住,这只在您多次调用同一个 API 时才有效。如果您调用不同的 API,这将不起作用。然而,在许多应用程序中,您拥有由 API 团队构建的 API,并且您将调用应用程序的相同吞吐量。

解决方案是使用 flutter http.Client。然后分享同样的http.Client然后在您对同一 API 进行的调用中您将看到只有第一个呼叫需要时间进行“连接”,其余呼叫不需要该时间。

flutter http pub page中有一个示例。它说 ,

如果您向同一服务器发出多个请求,则可以使用客户端保持打开的持久连接,而不是发出一次性请求。如果您这样做,请确保完成后关闭客户端:

检查下面的例子。仅供参考,并非最佳使用方法。

主程序.dart

import 'package:flutter/material.dart';
import 'package:network_test/role_service.dart';
import 'package:network_test/user_role_service.dart';
import 'package:network_test/user_service.dart';
import 'package:http/http.dart' as http;

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var startTime = "";
  var endTime = "";

  void _network() async {
    var client = http.Client();

    RoleService _roleService = RoleService();
    UserService _userService = UserService();
    UserRoleService _userRoleService = UserRoleService();

    String authToken = "****";

    String uid = "555555";
    try {
      await _roleService.getAllRoles(authToken, client);
      //await _roleService.getAllRoles(authToken, client);
      await _userService.getUserByUID(authToken, uid, client);
      await _userService.getUserByID(authToken, 27, client);
      await _userRoleService.getUserRoleByUser(authToken, 27, client);
    } finally {
      client.close();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              "Start Time: " + startTime,
              style: Theme.of(context).textTheme.headline4,
            ),
            Text(
              "End Time: " + endTime,
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _network,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

角色服务.dart

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'package:network_test/role.dart';
import 'dart:convert' as convert;
import 'dart:io';

class RoleService with ChangeNotifier {
  late List<Role> _roles;
  String link2 = "https://api2.somewhere.com/userrel";

  /// Return roles
  List<Role> returnRoles() {
    return _roles;
  }

  /// Get all Roles
  Future<void> getAllRoles(String authToken, Client client) async {
    try {
      var data = await client.get(Uri.parse(link2 + "/role/getall"),
          headers: {HttpHeaders.authorizationHeader: "Bearer $authToken"});

     
      var jsonData =
          convert.json.decode(data.body).cast<Map<String, dynamic>>();
      _roles = jsonData.map<Role>((json) => Role.fromJson(json)).toList();
      print(_roles[0].roleName);
    } catch (error) {
      print(error);
      throw error;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我告诉你上面不是最佳实践。为什么?因为你将http.Client在许多不同的地方创造和摧毁。让我们关注更好的实践。

几乎在每个应用程序中,我们都使用状态管理。我是 的粉丝Provider,它可以是你选择的任何东西。我想出最好的办法就是让状态管理记住.的创建http.Client。由于我正在使用Provider,我创建了以下类。

import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';

class ConnectionService with ChangeNotifier {
  http.Client _client = http.Client();

  http.Client returnConnection() {
    return _client;
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的主课

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  runApp(MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (context) => ConnectionService()),
    ],
    child: MyApp(),
  ));
}
Run Code Online (Sandbox Code Playgroud)

现在,当应用程序打开时,我调用该类ConnectionService来建立连接并执行 API 调用,例如检查用户身份验证、用户访问权限等。只有第一个调用需要时间来建立连接,其他调用则不会。