一、引入

  1. 七牛云的官方SDK中只有单图上传。如果想要实现多图的上传可能会想到for循环,递归等解决方案.在这里我分享下我用RxJava+回调接口封装的七牛云多图上传工具类,也算是之前看了老多RxJava文章的一个实践吧。如有不妥之处,还请多多指教啦😁

二、先简单说下七牛

我们公司的项目是图片直接由客户端上传的七牛,然后在给我们服务器传七牛的地址。

  1. 引入依赖
  1. implementation 'com.qiniu:qiniu-android-sdk:7.3.+'
  1. 七牛的图片上传
  1. // 吐槽一下:token 官方推荐服务器生成,可是我司都是客户端自己搞。。。
  2. // UploadManager uploadManager = new UploadManager(config);
  3. data = <File对象、或 文件路径、或 字节数组>
  4. String key = <指定七牛服务上的文件名,或 null>;
  5. String token = <从服务端SDK获取>;
  6. uploadManager.put(data, key, token,
  7. new UpCompletionHandler() {
  8. @Override
  9. public void complete(String key, ResponseInfo info, JSONObject res) {
  10. //res包含hash、key等信息,具体字段取决于上传策略的设置
  11. if(info.isOK()) {
  12. Log.i("qiniu", "Upload Success");
  13. } else {
  14. Log.i("qiniu", "Upload Fail");
  15. //如果失败,这里可以把info信息上报自己的服务器,便于后面分析上传错误原因
  16. }
  17. Log.i("qiniu", key + ",\r\n " + info + ",\r\n " + res);
  18. }
  19. }, null);

三、在说几个Rxjava的方法哈哈

括号中的内容为在当前项目中的用途

  1. fromIterable(发送原始数据,图片地址集合)

可以接收一个 Iterable 容器作为输入,每次发射一个元素

  1. flatMap(将图片地址转为七牛云上传成功后的文件名,具体看代码吧)

FlatMap操作符使用一个指定的函数对原始Observable发射的每一项数据执行变换操作,这个函数返回一个本身也发射数据的Observable,然后FlatMap合并这些Observables发射的数据,最后将合并后的结果当做它自己的数据序列发射。

  1. compose(切换线程)

compose()是唯一一个能够从数据流中得到原始Observable的操作符,所以,那些需要对整个数据流产生作用的操作(比如,subscribeOn()和observeOn())需要使用compose()来实现。

  1. 为什么不用compose进行变换

答:因为compose是操作的整个流,FlatMap是操作的单独的事件。

四、工具类代码

  1. public class QiNiuUtils {
  2. private static String token = "一般是找自己服务器要";
  3. /**
  4. * 七牛云SDK
  5. */
  6. private static UploadManager uploadManager = new UploadManager();
  7. /**
  8. * 回调接口
  9. */
  10. public interface QiNiuCallback {
  11. /**
  12. * 上传完成
  13. */
  14. void onSuccess(List<String> picUrls);
  15. /**
  16. * 上传失败
  17. */
  18. void onError(String msg);
  19. }
  20. /**
  21. * 上传图片到七牛
  22. *
  23. * @param images 图片地址
  24. * @param qiNiuCallback 回调接口
  25. */
  26. @SuppressLint("CheckResult")
  27. public static void putImgs(List<String> images, QiNiuCallback qiNiuCallback) {
  28. // 七牛返回的文件名
  29. ArrayList<String> resultImagePath = new ArrayList<>();
  30. Observable
  31. // 依次发送list中的数据
  32. .fromIterable(images)
  33. // 变换,在这里上传图片
  34. .flatMap((Function<String, ObservableSource<String>>)
  35. path -> Observable.create(emitter -> {
  36. String key = UUID.randomUUID().toString() + "." + path.split("\\.")[1];
  37. uploadManager.put(path, key, token,
  38. (key1, info, res) -> {
  39. //res包含hash、key等信息,具体字段取决于上传策略的设置
  40. if (info.isOK()) {
  41. // 上传成功,发送这张图片的文件名
  42. emitter.onNext(key1);
  43. } else {
  44. // 上传失败,告辞
  45. emitter.onError(new IOException(info.error));
  46. }
  47. }, null);
  48. })
  49. )
  50. // 线程切换
  51. .compose(RxUtil.rxObservableSchedulerHelper())
  52. .subscribe(response -> {
  53. resultImagePath.add(response);
  54. // 如果全部完成,调用成功接口
  55. if (resultImagePath.size() == images.size()) {
  56. qiNiuCallback.onSuccess(resultImagePath);
  57. }
  58. }, throwable -> {
  59. LogUtils.e(throwable.getMessage());
  60. qiNiuCallback.onError(throwable.getMessage());
  61. });
  62. }
  63. }

六、7月30日更新

为了确保图片顺序,将flatMap修改为concatMap

注意:emitter.onComplete();

  1. public static void putImgs(List<String> images, QiNiuCallback qiNiuCallback) {
  2. String token = Auth.create(Constants.QINIU_AK, Constants.QINIU_SK).uploadToken(Constants.QINIU_SCOPE);
  3. // 七牛返回的文件名
  4. ArrayList<String> resultImagePath = new ArrayList<>();
  5. Observable
  6. // 依次发送list中的数据
  7. .fromIterable(images)
  8. // 变换,在这里上传图片
  9. // 修改为concatMap确保图片顺序
  10. .concatMap((Function<String, ObservableSource<String>>) path ->
  11. Observable.create((ObservableOnSubscribe<String>) emitter -> {
  12. String key = UUID.randomUUID().toString() + "." + path.split("\\.")[1];
  13. ResponseInfo responseInfo = uploadManager.syncPut(path, key, token, null);
  14. if (responseInfo.isOK()) {
  15. // 上传成功,发送这张图片的文件名
  16. emitter.onNext(key);
  17. emitter.onComplete();
  18. } else {
  19. // 上传失败,告辞
  20. emitter.onError(new IOException(responseInfo.error));
  21. }
  22. }).subscribeOn(Schedulers.io())
  23. )
  24. // 线程切换
  25. .observeOn(AndroidSchedulers.mainThread())
  26. .subscribe(response -> {
  27. resultImagePath.add(response);
  28. // 如果全部完成,调用成功接口
  29. if (resultImagePath.size() == images.size()) {
  30. qiNiuCallback.onSuccess(resultImagePath);
  31. }
  32. }, throwable -> {
  33. LogUtils.e(throwable.getMessage());
  34. qiNiuCallback.onError(throwable.getMessage());
  35. });
  36. }

七、相关链接

七牛云文档:https://developer.qiniu.com/kodo/sdk/1236/android

RxJava的简单使用:https://www.sdwfqin.com/2016/12/25/rxjava的简单使用/