flutter开发实战-文件上传及上传队列

之前开发中遇到了发帖子图片上传,上传到七牛。

一、实现Dio上传

上传使用到Dio上传功能,具体代码

// 上传文件(图片)
  doUploadFile(String url, UploadFileInfo fileInfo,
      {Map<String, dynamic>? params,
      OnUploaded? uploaded,
      OnFailure? failure}) async {
    try {
      String timeStamp = DateTime.now().millisecondsSinceEpoch.toString();
      Map<String, dynamic> fromParams = Map();
      if (params != null && params.isNotEmpty) {
        fromParams.addAll(params);
      }

      fromParams["file"] = await MultipartFile.fromFile(fileInfo.file.path,
          filename: '${fileInfo.key}-${timeStamp}.jpg');

      FormData formData = FormData.fromMap(fromParams);
      Response? response = await dio.post(url, data: formData);
      assert(() {
        // assert只会在debug模式下执行,release模式下不会执行
        // 打印信息
        LoggerManager().error('''api: $url\nresult: $response''');
        return true;
      }());

      if (response != null) {
        Map<String, dynamic> result = json.decode(response.toString());
        assert(() {
          // assert只会在debug模式下执行,release模式下不会执行
          // 打印信息
          LoggerManager().debug('''api: $url\nresult: $result''');
          return true;
        }());

        if (response.statusCode == 200) {
          if (uploaded != null) {
            uploaded(result);
          }
        } else {
          //返回失败信息
          LoggerManager().error('''api: $url\nresult: $result''');

          ApiHttpError apiHttpError =
              ApiHttpError(ApiHttpErrorType.Default, "请求失败!");

          if (failure != null) {
            failure(apiHttpError);
          }
        }
      } else {
        //返回失败信息
        // 没有获得response,failure
        ApiHttpError apiHttpError =
            ApiHttpError(ApiHttpErrorType.Default, "请求失败!");

        if (failure != null) {
          failure(apiHttpError);
        }
      }
    } on DioError catch (e, s) {
      // catch到异常,failure
      LoggerManager().error("doUploadFile api: $url, dioError:$e, s:$s");
      ApiHttpError apiHttpError = getRequestFailure(e.response, e.type);

      if (failure != null) {
        failure(apiHttpError);
      }
    } catch (e) {
      // 可以捕获任意异常
      ApiHttpError apiHttpError =
          ApiHttpError(ApiHttpErrorType.Default, "${e.toString()}");

      if (failure != null) {
        failure(apiHttpError);
      }
    }
  }

二、实现上传到七牛uploader_tool

上传七牛需要获取上传七牛的token

void getQiniuToken(
      {required Function(String token) completion,
      required Function(ApiHttpError) failure}) {
    QiniuTokenRequest request = QiniuTokenRequest();
    GApiRepository.getQiniuToken(
      request: request,
      success: (response) async {
        Map<String, dynamic>? object = response.object;
        String token = "";
        if (object != null && object.isNotEmpty) {
          token = object["uptoken"];
        }

        if (completion != null) {
          completion(token);
        }
      },
      failure: (error) {
        if (failure != null) {
          failure(error);
        }
      },
    );
  }

调用doUploadFile实现上传

const String kQiniuUpHost = "http://up.qiniu.com";
const String kQiniuUndefinedKey = "?";
const String kQiniuUserAgent = "qiniu-ios-sdk";

const String kBucket = "bucket";
const String kQiniuDomainPreUrl = "domain";


void uploadImage(String imagePath, String token, {required Function(String key) completion,
    required Function(ApiHttpError) failure}) {
    String? key = StringUtils.toMD5(imagePath);
    String random = StringUtils.getRandom(10);
    String imageKey = "${key}-${random}";

    Map<String, dynamic> params = Map();
    params["bucket"] = "avatar";
    params["x:id"] = imageKey;
    params["token"] = token;
    params["User-Agent"] = kQiniuUserAgent;

    UploadFileInfo fileInfo =
    UploadFileInfo(file: File(imagePath), key: imageKey);

    HttpApi().doUploadFile(
      kQiniuUpHost,
      fileInfo,
      params: params,
      uploaded: (Map<String, dynamic> result) {
        String? aResultKey = result["key"];
        completion(aResultKey ?? "");
      },
      failure: (ApiHttpError error) {
        failure(error);
      },
    );
  }

三、实现上传队列

简单实现上传队列,这里上传采用一个接着一个上传,

代码如下

class UploaderQueue {

  // imagePath - key
  Function(Map<String, String> keys)? completion;

  Function(ApiHttpError error)? failure;

  UploaderQueue({
    this.completion,
    this.failure,
  });

  // 是否有任务正在进行时
  bool _isUploading = false;

  // 任务列表
  final List<String> _imagePathList = [];

  // 上传的keys
  final Map<String, String> _keyMap = {};

  // 上传的服务
  final UploaderTool _uploaderService = UploaderTool();

  void addImagePaths(List<String> imagePaths) {
    if (_isUploading) {
      return;
    }
    _imagePathList.addAll(imagePaths);
  }

  void doUpload() {
    if (_imagePathList.isEmpty) {
      return;
    }

    if (_isUploading) {
      return;
    }

    _isUploading = true;
    // 获取当前上传的图片ImagePath
    String imagePath = _imagePathList[0];

    _uploaderService.uploaderImage(imagePath, completion: (String key) {
      if (key.isNotEmpty) {
        _keyMap[imagePath] = key;
      }

      // 出队列
      _imagePathList.removeAt(0);
      _isUploading = false;

      if (_imagePathList.isNotEmpty) {
        // 不为空的时候
        doUpload();
      } else {
        if (completion != null) {
          completion!(_keyMap);
        }
      }
    }, failure: (ApiHttpError error) {
      cancel();
      if (failure != null) {
        failure!(error);
      }
    });
  }

  void cancel() {
    _isUploading = false;
    _imagePathList.clear();
  }

  void clear() {
    _isUploading = false;
    _imagePathList.clear();
  }
}

四、小结

flutter开发实战-文件上传及上传队列,获取token,上传图片到七牛。

学习记录,每天不停进步。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐