Flutter: как увеличить количество вызовов onSendProgress для плавной анимации индикатора выполнения при загрузке файлов? - PullRequest
9 голосов
/ 06 мая 2020

У меня есть следующий код для загрузки файла.

var client = new dio.Dio();
await client.put(
  url,
  data: formData,
  options: dio.Options(
    headers: headers,
  ),
  onSendProgress: (int sent, int total) {
    final progress = sent / total;
    print('progress: $progress ($sent/$total)');
  },
);

Загрузка файла работает нормально. Дело в том, что у меня есть представление с круговой шкалой выполнения, которая указывает прогресс загрузки при запуске onSendProgress. Когда я загружаю файл размером ~ 10 МБ, индикатор выполнения перескакивает с 0% на 100% в течение секунды, а затем ждет пару секунд (в зависимости от размера файла), прежде чем продолжить выполнение остальной части кода. Мне это кажется странным, потому что я ожидаю, что индикатор выполнения будет постепенно увеличивать свой прогресс.

Ниже вы можете найти результаты печати из моего примера с файлом размером ~ 10 МБ.

flutter: progress: 0.000003035281907563734 (29/9554302)
flutter: progress: 0.000013187776563897604 (126/9554302)
flutter: progress: 0.999996546058519 (9554269/9554302)
flutter: progress: 0.9999967553883057 (9554271/9554302)
flutter: progress: 1.0 (9554302/9554302)

Этот имеет файл меньшего размера, но такое же количество обратных вызовов.

flutter: progress: 0.00001847214941293598 (29/1569931)
flutter: progress: 0.00008025830434585978 (126/1569931)
flutter: progress: 0.9999789799679094 (1569898/1569931)
flutter: progress: 0.9999802539092483 (1569900/1569931)
flutter: progress: 1.0 (1569931/1569931)

Как вы можете видеть, он перескакивает с 0% на 100%. Я могу представить, как вы думаете, что это просто быстрый inte rnet. Но я пробовал Wi-Fi, 4G, 3G, и все они показывают одну и ту же проблему. Я нажимаю кнопку загрузки, она начинается с 0%, она переходит на 100%, а затем мне нужно подождать некоторое время (в зависимости от размера файла) для загрузки в fini sh.

Есть ли способ чтобы получить больше onSendProgress обратных вызовов, запущенных во время загрузки, или как-то отложить загрузку, чтобы я мог добиться плавного процесса загрузки?

EDIT:

Я пробовал следующее с Пакет HTTP

import 'dart:async';
import 'package:http/http.dart' as http;

class UploadRequest extends http.MultipartRequest {
  final void Function(int bytes, int totalBytes) onProgress;

  UploadRequest(
    String method,
    Uri url, {
    this.onProgress,
  }) : super(method, url);

  http.ByteStream finalize() {
    final byteStream = super.finalize();
    if (onProgress == null) return byteStream;

    final total = this.contentLength;

    final t = StreamTransformer.fromHandlers(
      handleData: (List<int> data, EventSink<List<int>> sink) {
        onProgress(data.length, total);
        sink.add(data);
      },
    );

    final stream = byteStream.transform(t);
    return http.ByteStream(stream);
  }
}

Триггер:

final request = UploadRequest(
  'PUT',
  Uri.parse(url),
  onProgress: (int bytes, int total) {
    print('progress: $progress ($sent/$total)');
  },
);

request.headers.addAll(headers);
request.files.add(
  http.MultipartFile.fromBytes(
    'file',
    attachment.file.buffer.asUint8List(),
    filename: attachment.name,
    contentType: MediaType.parse(attachment.contentType),
  ),
);


var response = await request.send();

Но, к сожалению, это та же проблема. Файл загружается нормально, но обратный вызов выполнения вызывается только несколько раз. Он сразу достигает 100%, затем мне нужно немного подождать (в зависимости от размера файла), прежде чем я получу ответ 2xx от сервера. Поэтому я не думаю, что это особая проблема c DIO.

Я думаю, что похоже, что на самом деле это не показывает прогресс загрузки, а скорее прогресс чтения файла в поток на стороне клиента. . Затем поток загружается на сервер, и это то, чего вы ждете (конечно, в зависимости от размера файла), даже если прогресс показывает 100%.

1 Ответ

2 голосов
/ 31 мая 2020

Похоже, это ошибка на dio, я вижу два способа обойти это:

  1. Просто добавьте число к вашему круговому прогрессу, он скажет 99% (обрезать остальное), чтобы пользователи знали, что это еще не сделано, поскольку 100% произойдет только тогда, когда вы получите 1.0 в результате).

  2. используйте http вместо этого. пакет http как StreamedRequest, который даст вам более точный контроль над тем, что отправляется, чтобы вы могли отразить это в своем пользовательском интерфейсе.

...