整理之前思考的如何通过选用的网络框架通过rxjava链式编程实现本地多张图片上传。
本地文件相册图片的选取 -->多个本地文件上传七牛-->拿到文件对应地址-->上传七牛图片地址到服务器
注:rxjava 的活学活用 :利用rxjava的多线程转换和map操作集替换亢余的代码for循环上传。
一. 整体逻辑步骤
二. rxjava代码具体实现
1. interface Api.java -->定义获取token接口
@GET(ConfigServer.GET_TOKEN)
Observable getUploadToken();
2. interface QiNiuApi.java -->定义七牛对应接口,baseUrl为七牛url
@Multipart
@POST("/")
Observable uploadImage(
@PartMap Map params);
3. interface Api.java -->定义客户端上传七牛文件地址到服务器接口
@POST(ConfigServer.UPLOAD_FILE)
@FormUrlEncoded
Observable
uploadFile(@Field(ConfigServer.PICTURES) String pictures);
4. class Req.java --> 代理模式封装类,retrofit 获取Api实现类,封装请求
private Req() {
Retrofit retrofit = BaseApi.getRetrofit();
mApi = retrofit.create(Api.class);
}
//获取token请求封装
public void getUploadToken(Subscriber subscriber) {
mApi.getUploadToken()
.compose(RxUtil.ioMain())
.subscribe(subscriber);
}
//上传文件请求封装
public void uploadFile(Subscriber subscriber,List pictures) {
JsonArray pictureJson = new JsonArray();
for (String picture : pictures) {
pictureJson.add(picture);
}
mApi.uploadFile(pictureJson.toString())
.compose(RxUtil.ioMain())
.subscribe(subscriber);
}
注:RxUtil -->异步线程切换
public static Observable.Transformer ioMain() {
return new Observable.Transformer() {
@Override
public Observable call(Observable tObservable) {
return tObservable.subscribeOn(Schedulers.io())
.unsubscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
5. QiNiuReq.java --> 代理模式封装类,retrofit 获取QiNiuApi实现类,封装请求
private QiNiuReq() {
Retrofit retrofit = BaseThirdApi.getRetrofit(BASE_URL);
mQiNiuApi = retrofit.create(QiNiuApi.class);
}
//获取七牛上传图片地址封装请求
public Observable getQiNiuBean(File file, String token, String key) {
Map params = new HashMap<>();
params.put("file", RequestBody.create(MediaType.parse("image/jpeg"), file));
params.put("token", RequestBody.create(MediaType.parse("text/plain"), token));
params.put("key", RequestBody.create(MediaType.parse("text/plain"), key));
return mQiNiuApi.uploadImage(params);
}
6. FileUtils.java --> 循环质压缩图片至200kb以下
/**
* 压缩图片
*
* @param context 当前上下文
* @param reqWidth 需要压缩的宽度尺寸
* @param reqHeight 需要压缩的高度尺寸
* @param maxCompressSize 压缩的最大图片大小,kb为单位
* @param filePath 需要被压缩的图片文件路径
* @return 成功压缩后的图片文件路径
*/
public static File compressPicBySampleSize(Context context, int reqWidth, int reqHeight, int maxCompressSize, String filePath) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
int outWidth = options.outWidth;
int outHeight = options.outHeight;
options.inSampleSize = findBestSampleSize(outWidth, outHeight, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
File file = new File(StorageUtils.getCacheDirectory(context, "image"), System.currentTimeMillis() + ".jpg");
BufferedOutputStream bos = null;
int quality = 100;
do {
if (quality < 20) {
break;
}
try {
bos = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
bos.flush();
quality -= 10;
} catch (Exception e) {
e.printStackTrace();
} finally {
IoUtils.closeStream(bos);
}
} while (file.length() > 1024 * maxCompressSize);
if (null != bitmap && !bitmap.isRecycled()) {
bitmap.recycle();
}
return file;
}
7. UploadPre.java --> 整体步骤通过rxjava串起来的逻辑交互类
--> rxjava链式编程:获取服务器token值
public void uploadProcess(final List pictures) {
Subscriber tokenSubscriber = new Subscriber(mActivity) {
@Override
public void onNextAction(final UploadTokenBean bean) {
compressFile(bean, title, content, orderId, products, pictures, themes, tags);
}
@Override
public void onErrorAction(int code) {
};
Req.getInstance().getUploadToken(tokenSubscriber);
}
--> rxjava 通过map集合:将本地图片压缩后返回压缩文件路径
private void compressFile(final UploadTokenBean bean,final List pictures) {
final List uploadPictures = new ArrayList<>();
Subscriber fileSubscriber = new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
mView.uploadFileFailed(-1);
}
@Override
public void onNext(File file) {
getQiNiuBean(file, bean,uploadPictures,pictures);
}
};
Observable.from(pictures).
subscribeOn(Schedulers.io())
.map(new Func1() {
@Override
public File call(String picture) {
return ImageUtil.compressPicBySampleSize(mActivity, 1000, 1000, 200, picture);
}
})
.observeOn(Schedulers.io())
.subscribe(fileSubscriber);
}
--> rxjava 链式编程 :上传本地图片到QiNiu服务器
private void getQiNiuBean(final File file,
final UploadTokenBean bean,
final List uploadPictures,
final List pictures) {
String key = Md5Utils.getFileMD5(file) + "." + FileUtil.getMineType(file);
SubscriberAdapter uploadSubscriber = new SubscriberAdapter() {
@Override
public void onCompleted() {
if (pictures.size() == uploadPictures.size()) {
upLoadFile( uploadPictures);
}
}
@Override
public void onError(Throwable e) {
if (mRetryCount > 0) {
mRetryCount--;
getQiNiuBean(file, bean, uploadPictures, pictures);
} else {
mRetryCount = 3;
mView.uploadFileFailed(-1);
}
}
@Override
public void onNext(QiNiuBean qiNiuBean) {
uploadPictures.add(qiNiuBean.getKey());
}
};
QiNiuReq.getInstance().getQiNiuBean(file, bean.getToken(), key).subscribe(uploadSubscriber);
}
--> rxjava 链式编程:上传文件七牛地址到服务器
private void upLoadFile(List uploadPictures) {
final Subscriber subscriber = new Subscriber(mActivity) {
@Override
public void onNextAction(JsonObject jsonObject) {
mView.upLoadFileSucceed();
}
@Override
public void onErrorAction(int code) {
mView.uploadFileFailed(code);
}
};
Req.getInstance().uploadFile(subscriber, uploadPictures);
}