整理之前思考的如何通過選用的網絡框架通過rxjava鏈式編程實現本地多張圖片上傳。
本地文件相冊圖片的選取 -->多個本地文件上傳七牛-->拿到文件對應地址-->上傳七牛圖片地址到服務器
注:rxjava 的活學活用 :利用rxjava的多線程轉換和map操作集替換亢余的代碼for循環上傳。
一. 整體邏輯步驟
image.png
二. rxjava代碼具體實現
1. interface Api.java -->定義獲取token接口
@GET(ConfigServer.GET_TOKEN)
Observable<UploadTokenBean> getUploadToken();
2. interface QiNiuApi.java -->定義七牛對應接口,baseUrl為七牛url
@Multipart
@POST("/")
Observable<QiNiuBean> uploadImage(
@PartMap Map<String, RequestBody> params);
3. interface Api.java -->定義客戶端上傳七牛文件地址到服務器接口
@POST(ConfigServer.UPLOAD_FILE)
@FormUrlEncoded
Observable<JsonObject>
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<UploadTokenBean> subscriber) {
mApi.getUploadToken()
.compose(RxUtil.<UploadTokenBean>ioMain())
.subscribe(subscriber);
}
//上傳文件請求封裝
public void uploadFile(Subscriber<JsonObject> subscriber,List<String> pictures) {
JsonArray pictureJson = new JsonArray();
for (String picture : pictures) {
pictureJson.add(picture);
}
mApi.uploadFile(pictureJson.toString())
.compose(RxUtil.<JsonObject>ioMain())
.subscribe(subscriber);
}
注:RxUtil -->異步線程切換
public static <T> Observable.Transformer<T, T> ioMain() {
return new Observable.Transformer<T, T>() {
@Override
public Observable<T> call(Observable<T> 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<QiNiuBean> getQiNiuBean(File file, String token, String key) {
Map<String, RequestBody> 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<String> pictures) {
Subscriber<UploadTokenBean> tokenSubscriber = new Subscriber<UploadTokenBean>(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<String> pictures) {
final List<String> uploadPictures = new ArrayList<>();
Subscriber<File> fileSubscriber = new Subscriber<File>() {
@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<String, File>() {
@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<String> uploadPictures,
final List<String> pictures) {
String key = Md5Utils.getFileMD5(file) + "." + FileUtil.getMineType(file);
SubscriberAdapter<QiNiuBean> uploadSubscriber = new SubscriberAdapter<QiNiuBean>() {
@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<String> uploadPictures) {
final Subscriber<JsonObject> subscriber = new Subscriber<JsonObject>(mActivity) {
@Override
public void onNextAction(JsonObject jsonObject) {
mView.upLoadFileSucceed();
}
@Override
public void onErrorAction(int code) {
mView.uploadFileFailed(code);
}
};
Req.getInstance().uploadFile(subscriber, uploadPictures);
}