Почему мои сетевые вызовы http flutter медленные?

#android #ios #flutter #http #dart

Вопрос:

Я разрабатываю приложение flutter с сетевыми действиями. Чтобы получить данные, я подключаюсь к a REST API , этот API работает быстро, как и должно быть.

Для получения дополнительной информации этот API использует AWS API Gateway и AWS 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;
    }
  }
}
 

Вы можете увидеть postman производительность вышеупомянутого API вызова ниже. Для тестирования флаттера я использую телефон Huawei p30 Lite на Android.

введите описание изображения здесь

Затем, когда я выполняю тот же API вызов в flutter, вот что я получаю.

введите описание изображения здесь

Наблюдая за выводами, postman я вижу, что он кэшировал поиск DNS, TCP-рукопожатие и SSL-рукопожатие. почтальон делает это после первого вызова URI базы API. Затем, начиная со 2-го раза, поиск DNS и т. Д. Кэшируются, экономя много времени при будущих вызовах API к тому же базовому URI.

Но в flutter время «Установления соединения» велико, даже несмотря на то, что время для извлечения данных составляет всего несколько миллисекунд.

Как я могу избежать задержек при подключении и получить максимальную производительность? Если кэширование SSL, поиск DNS и т.д. Является решением, как я могу сделать это в flutter?

Комментарии:

1. Вы пробовали тестировать в режиме профиля?

2. Не могли бы вы попробовать speedtest.net на вашем устройстве? Я бы не ожидал, что вы оптимизируете сетевые запросы Flutter, выполняя подобное кэширование.

3. @7mada мне удалось найти решение самостоятельно. я опубликовал ответ.

4. @BenButterworth: мне удалось найти решение самостоятельно. я опубликовал ответ.

Ответ №1:

Похоже, этот вопрос существует для многих людей. Итак, позвольте мне ответить на мой собственный вопрос.

Может ли флаттер запомнить сетевое подключение? Да, это возможно.

Для Flutter требуется только один сетевой вызов одного и того же API, чтобы запомнить соединение. Начиная со второго вызова того же API, он будет использовать свою «кэшированную» память, что значительно повысит производительность.

Поэтому сначала помните, что это работает только в том случае, если вы вызываете один и тот же API несколько раз. Если вы вызываете разные API, это не сработает. Однако во многих приложениях у вас есть API, созданный командой API, и вы будете вызывать то же самое приложение.

Решение состоит в том, чтобы использовать http flutter.Клиент. Затем поделитесь тем же http.Client самым между вызовами, которые вы совершаете в один и тот же API. Вы увидите, что только первый звонок требует времени для «подключения», остальные звонки не занимают этого времени.

Пример доступен на странице http-паба flutter. В нем говорится: ,

Если вы делаете несколько запросов к одному и тому же серверу, вы можете сохранить постоянное соединение с помощью клиента, а не выполнять разовые запросы. Если вы сделаете это, обязательно закройте клиента, когда закончите:

Проверьте пример ниже. Это только для вашей справки, не лучший способ использовать это.

главная.дротик

 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),
      ),
    );
  }
}
 

role_service.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;
    }
  }
}
 

теперь я сказал вам, что вышесказанное-не лучшая практика. Почему? Потому что вы будете создавать и разрушать 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;
  }
}
 

И это мой основной урок

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

  runApp(MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (context) => ConnectionService()),
    ],
    child: MyApp(),
  ));
}
 

Теперь, когда приложение открывается, я вызываю ConnectionService класс для подключения и выполняю свои вызовы API, такие как проверка подлинности пользователя, доступ пользователя и т.д. И только первый звонок не торопится устанавливать соединение, другие звонки этого не делают.

Комментарии:

1. не могли бы вы, пожалуйста, загрузить реализацию riverpod