feat: 增加文件分片上传功能
This commit is contained in:
parent
1b6024d0cb
commit
8706bb1243
@ -1,4 +1,7 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
@ -83,6 +86,7 @@ dependencies {
|
||||
implementation 'com.lzy.net:okgo:3.0.4'
|
||||
implementation 'com.lzy.net:okrx2:2.0.2'
|
||||
implementation 'com.google.code.gson:gson:2.8.5'
|
||||
implementation 'com.readystatesoftware.chuck:library:1.0.4'
|
||||
|
||||
//retrofit+rxJava
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
|
||||
@ -128,7 +132,8 @@ dependencies {
|
||||
def room_version = "2.2.0-alpha01"
|
||||
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
annotationProcessor "androidx.room:room-compiler:$room_version"
|
||||
implementation "androidx.room:room-ktx:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
implementation "androidx.room:room-rxjava2:$room_version"
|
||||
implementation "androidx.room:room-guava:$room_version"
|
||||
testImplementation "androidx.room:room-testing:$room_version"
|
||||
|
@ -245,6 +245,8 @@ public class Constant {
|
||||
|
||||
public static Set<String> submitIdSet = new HashSet<>();
|
||||
public static final String SUBMIT_TOAST_MSG= "当前POI已经在提交列表中,无需重复提交!";
|
||||
public static final long DEFAULT_CUT_SIZE = 5*1024*1024; // 文件切分默认大小为5MB
|
||||
public static final int DEFAULT_TIME_OUT = 300; // 默认http超时时间设置为300秒
|
||||
|
||||
public static void clearLoginInfo() {
|
||||
ACCESS_TOKEN = null;
|
||||
|
@ -0,0 +1,276 @@
|
||||
package com.navinfo.outdoor.bean;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.lzy.okgo.OkGo;
|
||||
import com.lzy.okgo.cache.CacheEntity;
|
||||
import com.lzy.okgo.cache.CacheMode;
|
||||
import com.lzy.okgo.convert.Converter;
|
||||
import com.lzy.okgo.convert.StringConvert;
|
||||
import com.lzy.okgo.model.HttpHeaders;
|
||||
import com.lzy.okgo.model.HttpParams;
|
||||
import com.lzy.okgo.model.Response;
|
||||
import com.lzy.okgo.request.GetRequest;
|
||||
import com.lzy.okgo.request.PostRequest;
|
||||
import com.lzy.okgo.request.base.Request;
|
||||
import com.navinfo.outdoor.api.Constant;
|
||||
import com.navinfo.outdoor.api.UserApplication;
|
||||
import com.navinfo.outdoor.http.Callback;
|
||||
import com.navinfo.outdoor.http.JsonCallback;
|
||||
import com.navinfo.outdoor.util.FlushTokenUtil;
|
||||
import com.navinfo.outdoor.util.Md5Util;
|
||||
import com.navinfo.outdoor.util.NetWorkUtils;
|
||||
import com.navinfo.outdoor.util.ToastUtils;
|
||||
import com.umeng.umcrash.UMCrash;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
public class CommonRequestSend<T extends CommonResponseBase> {
|
||||
public void getMethodCommon(Activity mContext, String url, HttpParams params, int timeOut, Callback<CommonResponse<T>> callback, Class<T> tClass) {
|
||||
try {
|
||||
Response<CommonResponse<T>> response = ((GetRequest<CommonResponse<T>>) obitainRequest(mContext, url, params, timeOut, 0, tClass))
|
||||
.adapt()
|
||||
.execute();
|
||||
if (response.code() == 200) {
|
||||
if (response.body().getCode() == 200) {
|
||||
callback.onSuccess(response.body(), 1);
|
||||
} else if (response.body().getCode() == 230){
|
||||
FlushTokenUtil.flushToken(mContext);
|
||||
Toast.makeText(mContext, "token过期,请重新登录后再试...", Toast.LENGTH_LONG).show();
|
||||
Throwable throwable = new Throwable("token过期,请重新登录后再试...");
|
||||
callback.onError(throwable, -1);
|
||||
/*
|
||||
* 友盟+
|
||||
* 使用自定义错误,查看时请在错误列表页面选择【自定义异常】
|
||||
*/
|
||||
UMCrash.generateCustomLog("网络请求报错-位置:OKGOBuilder" + throwable, "UmengException");
|
||||
} else {
|
||||
Toast.makeText(mContext, response.message(), Toast.LENGTH_LONG).show();
|
||||
Throwable throwable = new Throwable(response.message());
|
||||
callback.onError(throwable, -2);
|
||||
/*
|
||||
* 友盟+
|
||||
* 使用自定义错误,查看时请在错误列表页面选择【自定义异常】
|
||||
*/
|
||||
UMCrash.generateCustomLog("网络请求报错-位置:OKGOBuilder" + throwable, "UmengException");
|
||||
}
|
||||
|
||||
} else {
|
||||
Toast.makeText(mContext, response.message(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Throwable throwable = e;
|
||||
if (throwable != null) {
|
||||
throwable.printStackTrace();
|
||||
callback.onError(throwable, -3);
|
||||
}
|
||||
/*
|
||||
* 友盟+
|
||||
* 使用自定义错误,查看时请在错误列表页面选择【自定义异常】
|
||||
*/
|
||||
UMCrash.generateCustomLog("网络请求报错-位置:OKGOBuilder" + throwable, "UmengException");
|
||||
}
|
||||
}
|
||||
|
||||
public CommonResponse<T> getMethodCommonSync(Activity mContext, String url, HttpParams params, int timeOut, Class<T> tClass) {
|
||||
try {
|
||||
Response<CommonResponse<T>> response = ((GetRequest<CommonResponse<T>>) obitainRequest(mContext, url, params, timeOut, 0, tClass))
|
||||
.adapt()
|
||||
.execute();
|
||||
if (response.code() == 200) {
|
||||
if (response.body().getCode() == 230){
|
||||
FlushTokenUtil.flushToken(mContext);
|
||||
}
|
||||
return response.body();
|
||||
} else {
|
||||
return new CommonResponse<T>(response.code(), response.message(), null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
String message = e.getMessage();
|
||||
assert message != null;
|
||||
if (message.equals("timeout") || message.equals("Read time out")) {
|
||||
ToastUtils.Message(mContext, "请求超时");
|
||||
} else {
|
||||
ToastUtils.Message(mContext, message);
|
||||
}
|
||||
Log.d("TAG", "onError: " + e.getMessage());
|
||||
return new CommonResponse<T>(e.hashCode(), e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public void postMethodCommon(Activity mContext, String url, HttpParams params, int timeOut, Callback<CommonResponse<T>> callback, Class<T> tClass) {
|
||||
try {
|
||||
Response<CommonResponse<T>> response = ((GetRequest<CommonResponse<T>>) obitainRequest(mContext, url, params, timeOut, 1, tClass))
|
||||
.adapt()
|
||||
.execute();
|
||||
if (response.code() == 200) {
|
||||
if (response.body().getCode() == 200) {
|
||||
callback.onSuccess(response.body(), 1);
|
||||
} else if (response.body().getCode() == 230){
|
||||
FlushTokenUtil.flushToken(mContext);
|
||||
Toast.makeText(mContext, "token过期,请重新登录后再试...", Toast.LENGTH_LONG).show();
|
||||
Throwable throwable = new Throwable("token过期,请重新登录后再试...");
|
||||
callback.onError(throwable, -1);
|
||||
/*
|
||||
* 友盟+
|
||||
* 使用自定义错误,查看时请在错误列表页面选择【自定义异常】
|
||||
*/
|
||||
UMCrash.generateCustomLog("网络请求报错-位置:OKGOBuilder" + throwable, "UmengException");
|
||||
} else {
|
||||
Toast.makeText(mContext, response.message(), Toast.LENGTH_LONG).show();
|
||||
Throwable throwable = new Throwable(response.message());
|
||||
callback.onError(throwable, -2);
|
||||
/*
|
||||
* 友盟+
|
||||
* 使用自定义错误,查看时请在错误列表页面选择【自定义异常】
|
||||
*/
|
||||
UMCrash.generateCustomLog("网络请求报错-位置:OKGOBuilder" + throwable, "UmengException");
|
||||
}
|
||||
|
||||
} else {
|
||||
Toast.makeText(mContext, response.message(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Throwable throwable = e;
|
||||
if (throwable != null) {
|
||||
throwable.printStackTrace();
|
||||
callback.onError(throwable, -3);
|
||||
}
|
||||
/*
|
||||
* 友盟+
|
||||
* 使用自定义错误,查看时请在错误列表页面选择【自定义异常】
|
||||
*/
|
||||
UMCrash.generateCustomLog("网络请求报错-位置:OKGOBuilder" + throwable, "UmengException");
|
||||
}
|
||||
}
|
||||
|
||||
public CommonResponse<T> postMethodCommonSync(Activity mContext, String url, HttpParams params, int timeOut, List<File> files, Class<T> tClass) {
|
||||
try {
|
||||
PostRequest<CommonResponse<T>> postRequest = (PostRequest<CommonResponse<T>>) obitainRequest(mContext, url, params, timeOut, 1, tClass);
|
||||
if (files!=null) {
|
||||
postRequest.addFileParams("file", files);
|
||||
}
|
||||
Response<CommonResponse<T>> response = postRequest
|
||||
.adapt()
|
||||
.execute();
|
||||
if (response.code() == 200) {
|
||||
if (response.body().getCode() == 230){
|
||||
FlushTokenUtil.flushToken(mContext);
|
||||
}
|
||||
return response.body();
|
||||
} else {
|
||||
return new CommonResponse<T>(response.code(), response.message(), null);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
String message = e.getMessage();
|
||||
assert message != null;
|
||||
if (message.equals("timeout") || message.equals("Read time out")) {
|
||||
ToastUtils.Message(mContext, "请求超时");
|
||||
} else {
|
||||
ToastUtils.Message(mContext, message);
|
||||
}
|
||||
Log.d("TAG", "onError: " + e.getMessage());
|
||||
return new CommonResponse<T>(e.hashCode(), e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成通用请求
|
||||
* @param requestType 0-默认为get请求,非0-post请求
|
||||
* */
|
||||
private Request obitainRequest(Activity mContext, String url, HttpParams params, int timeOut, int requestType, Class<T> clazz) throws Exception{
|
||||
if (!NetWorkUtils.iConnected(UserApplication.userApplication)) { // 当前网络不可用
|
||||
throw new Exception("网络不可用");
|
||||
}
|
||||
initTimeOut(timeOut);
|
||||
long time = System.currentTimeMillis();
|
||||
params.put("datetime", time);
|
||||
Request request = null;
|
||||
if (requestType != 0) {
|
||||
request= OkGo
|
||||
// 请求方式和请求url
|
||||
.<CommonResponse<T>>post(url);
|
||||
} else {
|
||||
request= OkGo
|
||||
// 请求方式和请求url
|
||||
.<CommonResponse<T>>get(url);
|
||||
}
|
||||
return request
|
||||
.headers(getHeader(params))
|
||||
.params(params)
|
||||
.retryCount(3)
|
||||
.converter(new MyJsonCallback(clazz) {
|
||||
@Override
|
||||
public void onSuccess(Response response) {
|
||||
|
||||
}
|
||||
})
|
||||
// 请求的 tag, 主要用于取消对应的请求
|
||||
.tag(this);
|
||||
}
|
||||
|
||||
private void initTimeOut(int time) {
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
builder.readTimeout(time, TimeUnit.SECONDS);
|
||||
//全局的写入超时时间
|
||||
builder.writeTimeout(time, TimeUnit.SECONDS);
|
||||
//全局的连接超时时间
|
||||
builder.connectTimeout(time, TimeUnit.SECONDS);
|
||||
builder.callTimeout(time, TimeUnit.SECONDS);
|
||||
OkGo.getInstance().init(UserApplication.getUserApplication()).setOkHttpClient(builder.build())
|
||||
//全局统一缓存模式,默认不使用缓存,可以不传
|
||||
.setCacheMode(CacheMode.NO_CACHE)
|
||||
//全局统一缓存时间,默认永不过期,可以不传
|
||||
.setCacheTime(CacheEntity.CACHE_NEVER_EXPIRE)
|
||||
.setRetryCount(3);
|
||||
}
|
||||
|
||||
private HttpHeaders getHeader(HttpParams params) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
try {
|
||||
if (Constant.ACCESS_TOKEN == null) {
|
||||
headers.put("Authorization", "Basic YXBwOmFwcHNlY3JldA==");
|
||||
} else {
|
||||
headers.put("Authorization", "bearer " + Constant.ACCESS_TOKEN);
|
||||
}
|
||||
StringBuilder util = new StringBuilder();//k1=v1&k2=v2&k3=v3
|
||||
if (params != null && params.urlParamsMap != null) {
|
||||
for (Map.Entry<String, List<String>> entry : params.urlParamsMap.entrySet()) {
|
||||
if (!"file".equals(entry.getKey())) {
|
||||
util.append(entry.getKey()).append("=").append(entry.getValue().get(0).toString()).append("&");
|
||||
}
|
||||
}
|
||||
if (!util.toString().equals("")) {
|
||||
util = new StringBuilder(util.substring(0, util.length() - 1));
|
||||
}
|
||||
}
|
||||
headers.put("key", Md5Util.toMD5("dtxb_2021_navinfo" + util));
|
||||
headers.put("Accept-Encoding", "identity");
|
||||
return headers;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.navinfo.outdoor.bean;
|
||||
|
||||
public class CommonResponse<T> extends CommonResponseBase{
|
||||
public CommonResponse(int code, String message, T body) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public CommonResponse() {
|
||||
}
|
||||
|
||||
protected T body;
|
||||
|
||||
public T getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(T body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.navinfo.outdoor.bean;
|
||||
|
||||
public class CommonResponseBase {
|
||||
protected Integer code;
|
||||
protected String message;
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public CommonResponse toLzyResponse() {
|
||||
CommonResponse lzyResponse = new CommonResponse();
|
||||
lzyResponse.code = code;
|
||||
lzyResponse.message = message;
|
||||
return lzyResponse;
|
||||
}
|
||||
}
|
72
app/src/main/java/com/navinfo/outdoor/bean/Convert.java
Normal file
72
app/src/main/java/com/navinfo/outdoor/bean/Convert.java
Normal file
@ -0,0 +1,72 @@
|
||||
package com.navinfo.outdoor.bean;
|
||||
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.readystatesoftware.chuck.internal.support.JsonConvertor;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class Convert {
|
||||
|
||||
private static Gson create() {
|
||||
return Convert.GsonHolder.gson;
|
||||
}
|
||||
|
||||
private static class GsonHolder {
|
||||
private static Gson gson = new Gson();
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Class<T> type) throws JsonIOException, JsonSyntaxException {
|
||||
return create().fromJson(json, type);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String json, Type type) {
|
||||
return create().fromJson(json, type);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
||||
return create().fromJson(reader, typeOfT);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException {
|
||||
return create().fromJson(json, classOfT);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
||||
return create().fromJson(json, typeOfT);
|
||||
}
|
||||
|
||||
public static String toJson(Object src) {
|
||||
return create().toJson(src);
|
||||
}
|
||||
|
||||
public static String toJson(Object src, Type typeOfSrc) {
|
||||
return create().toJson(src, typeOfSrc);
|
||||
}
|
||||
|
||||
public static String formatJson(String json) {
|
||||
try {
|
||||
JsonParser jp = new JsonParser();
|
||||
JsonElement je = jp.parse(json);
|
||||
return JsonConvertor.getInstance().toJson(je);
|
||||
} catch (Exception e) {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatJson(Object src) {
|
||||
try {
|
||||
JsonParser jp = new JsonParser();
|
||||
JsonElement je = jp.parse(toJson(src));
|
||||
return JsonConvertor.getInstance().toJson(je);
|
||||
} catch (Exception e) {
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
128
app/src/main/java/com/navinfo/outdoor/bean/MyJsonCallback.java
Normal file
128
app/src/main/java/com/navinfo/outdoor/bean/MyJsonCallback.java
Normal file
@ -0,0 +1,128 @@
|
||||
package com.navinfo.outdoor.bean;
|
||||
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.lzy.okgo.callback.AbsCallback;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
public abstract class MyJsonCallback<T> extends AbsCallback<T> {
|
||||
|
||||
private Type type;
|
||||
private Class<T> clazz;
|
||||
|
||||
public MyJsonCallback() {
|
||||
}
|
||||
|
||||
public MyJsonCallback(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public MyJsonCallback(Class<T> clazz) {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T convertResponse(Response response) throws Throwable {
|
||||
|
||||
if (type == null) {
|
||||
if (clazz == null) {
|
||||
// 如果没有通过构造函数传进来,就自动解析父类泛型的真实类型(有局限性,继承后就无法解析到)
|
||||
Type genType = getClass().getGenericSuperclass();
|
||||
type = ((ParameterizedType) genType).getActualTypeArguments()[0];
|
||||
} else {
|
||||
return parseClass(response, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
if (type instanceof ParameterizedType) {
|
||||
return parseParameterizedType(response, (ParameterizedType) type);
|
||||
} else if (type instanceof Class) {
|
||||
return parseClass(response, (Class<?>) type);
|
||||
} else {
|
||||
return parseType(response, type);
|
||||
}
|
||||
}
|
||||
|
||||
private T parseClass(Response response, Class<?> rawType) throws Exception {
|
||||
if (rawType == null) return null;
|
||||
ResponseBody body = response.body();
|
||||
if (body == null) return null;
|
||||
JsonReader jsonReader = new JsonReader(body.charStream());
|
||||
|
||||
if (rawType == String.class) {
|
||||
//noinspection unchecked
|
||||
return (T) body.string();
|
||||
} else if (rawType == JSONObject.class) {
|
||||
//noinspection unchecked
|
||||
return (T) new JSONObject(body.string());
|
||||
} else if (rawType == JSONArray.class) {
|
||||
//noinspection unchecked
|
||||
return (T) new JSONArray(body.string());
|
||||
} else {
|
||||
T t = Convert.fromJson(jsonReader, rawType);
|
||||
response.close();
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
private T parseType(Response response, Type type) throws Exception {
|
||||
if (type == null) return null;
|
||||
ResponseBody body = response.body();
|
||||
if (body == null) return null;
|
||||
JsonReader jsonReader = new JsonReader(body.charStream());
|
||||
|
||||
// 泛型格式如下: new JsonCallback<任意JavaBean>(this)
|
||||
T t = Convert.fromJson(jsonReader, type);
|
||||
response.close();
|
||||
return t;
|
||||
}
|
||||
|
||||
private T parseParameterizedType(Response response, ParameterizedType type) throws Exception {
|
||||
if (type == null) return null;
|
||||
ResponseBody body = response.body();
|
||||
if (body == null) return null;
|
||||
JsonReader jsonReader = new JsonReader(body.charStream());
|
||||
|
||||
Type rawType = type.getRawType(); // 泛型的实际类型
|
||||
Type typeArgument = type.getActualTypeArguments()[0]; // 泛型的参数
|
||||
if (rawType != CommonResponse.class) {
|
||||
// 泛型格式如下: new JsonCallback<外层BaseBean<内层JavaBean>>(this)
|
||||
T t = Convert.fromJson(jsonReader, type);
|
||||
response.close();
|
||||
return t;
|
||||
} else {
|
||||
if (typeArgument == Void.class) {
|
||||
// 泛型格式如下: new JsonCallback<LzyResponse<Void>>(this)
|
||||
CommonResponseBase simpleResponse = Convert.fromJson(jsonReader, CommonResponseBase.class);
|
||||
response.close();
|
||||
//noinspection unchecked
|
||||
return (T) simpleResponse.toLzyResponse();
|
||||
} else {
|
||||
// 泛型格式如下: new JsonCallback<LzyResponse<内层JavaBean>>(this)
|
||||
CommonResponse lzyResponse = Convert.fromJson(jsonReader, type);
|
||||
response.close();
|
||||
int code = lzyResponse.code;
|
||||
// 一般来说服务器会和客户端约定一个数表示成功,如200,其余的表示失败,如400,300等,这里根据实际情况罗列并抛出
|
||||
if (code == 0) {
|
||||
//noinspection unchecked
|
||||
return (T) lzyResponse;
|
||||
} else if (code == 230) {
|
||||
throw new IllegalStateException("Token已过期");
|
||||
} /*else if (code == 300) {
|
||||
throw new IllegalStateException("用户名密码错误");
|
||||
} */else {
|
||||
// 直接将服务端的错误信息抛出,onError中可以获取
|
||||
throw new IllegalStateException("错误代码:" + code + ",错误信息:" + lzyResponse.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -52,6 +52,7 @@ import com.navinfo.outdoor.room.PoiDao;
|
||||
import com.navinfo.outdoor.room.PoiDatabase;
|
||||
import com.navinfo.outdoor.room.PoiEntity;
|
||||
import com.navinfo.outdoor.util.AWMp4ParserHelper;
|
||||
import com.navinfo.outdoor.util.DataSaveUtils;
|
||||
import com.navinfo.outdoor.util.FlushTokenUtil;
|
||||
import com.navinfo.outdoor.util.Geohash;
|
||||
import com.navinfo.outdoor.util.GeometryTools;
|
||||
@ -507,42 +508,62 @@ public class PoiVideoFragment extends BaseDrawerFragment implements View.OnClick
|
||||
ToastUtils.Message(getActivity(), "本地不存在照片文件,无法上传数据,请确认!");
|
||||
return;
|
||||
}
|
||||
fileZip = new File(Constant.PICTURE_FOLDER, "files" + ".zip");
|
||||
new Thread(new Runnable() {
|
||||
DataSaveUtils.getInstance().uploadFiles(getActivity(), showPoiEntity, videoFileList, new DataSaveUtils.UploadCallback() {
|
||||
@Override
|
||||
public void run() {
|
||||
ZipUtil.zipFiles(videoFileList, fileZip, null);
|
||||
long zipTrueSize = ZipUtils.getZipTrueSize(fileZip.getAbsolutePath());
|
||||
if (zipTrueSize > 0) {
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (showPoiEntity == null) {
|
||||
showPoiEntity = new PoiEntity();
|
||||
}
|
||||
if (showPoiEntity.getTaskStatus() == 0 || showPoiEntity.getTaskStatus() == 1 || showPoiEntity.getTaskStatus() == 2 || showPoiEntity.getTaskStatus() == 5) {
|
||||
initPoiSaveLocal(true);
|
||||
} else {
|
||||
poiVideoUpload(showPoiEntity.getBodyId(), fileZip);
|
||||
Constant.isPresent = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fileZip.delete();
|
||||
ToastUtils.Message(getActivity(), "压缩文件失败,请重新提交");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
public void onStart() {
|
||||
dismissLoadingDialog();
|
||||
Constant.isPresent = false;
|
||||
getActivity().getSupportFragmentManager().popBackStack();//回退
|
||||
WaitDialog.show((AppCompatActivity) getActivity(), "任务正在后台上传中,请稍候...");
|
||||
WaitDialog.dismiss(3000);
|
||||
}
|
||||
}).start();
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
Constant.isPresent = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
|
||||
}
|
||||
});
|
||||
// fileZip = new File(Constant.PICTURE_FOLDER, "files" + ".zip");
|
||||
// new Thread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// ZipUtil.zipFiles(videoFileList, fileZip, null);
|
||||
// long zipTrueSize = ZipUtils.getZipTrueSize(fileZip.getAbsolutePath());
|
||||
// if (zipTrueSize > 0) {
|
||||
// if (getActivity() != null) {
|
||||
// getActivity().runOnUiThread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// if (showPoiEntity == null) {
|
||||
// showPoiEntity = new PoiEntity();
|
||||
// }
|
||||
// if (showPoiEntity.getTaskStatus() == 0 || showPoiEntity.getTaskStatus() == 1 || showPoiEntity.getTaskStatus() == 2 || showPoiEntity.getTaskStatus() == 5) {
|
||||
// initPoiSaveLocal(true);
|
||||
// } else {
|
||||
// poiVideoUpload(showPoiEntity.getBodyId(), fileZip);
|
||||
// Constant.isPresent = false;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// } else {
|
||||
// if (getActivity() != null) {
|
||||
// getActivity().runOnUiThread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// fileZip.delete();
|
||||
// ToastUtils.Message(getActivity(), "压缩文件失败,请重新提交");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }).start();
|
||||
} else {
|
||||
dismissLoadingDialog();
|
||||
ToastUtils.Message(getActivity(), "请录像");
|
||||
|
@ -44,6 +44,7 @@ import com.navinfo.outdoor.activity.FragmentManagement;
|
||||
import com.navinfo.outdoor.activity.PicturesActivity;
|
||||
import com.navinfo.outdoor.api.Constant;
|
||||
import com.navinfo.outdoor.base.BaseDrawerFragment;
|
||||
import com.navinfo.outdoor.util.DataSaveUtils;
|
||||
import com.navinfo.outdoor.util.FlushTokenUtil;
|
||||
import com.navinfo.outdoor.util.PoiSaveUtils;
|
||||
import com.navinfo.outdoor.util.PreserveUtils;
|
||||
@ -584,42 +585,62 @@ public class RoadFragment extends BaseDrawerFragment implements View.OnClickList
|
||||
ToastUtils.Message(getActivity(), "本地不存在照片文件,无法上传数据,请确认!");
|
||||
return;
|
||||
}
|
||||
fileZip = new File(Constant.PICTURE_FOLDER, "files" + ".zip");
|
||||
new Thread(new Runnable() {
|
||||
DataSaveUtils.getInstance().uploadFiles(getActivity(), showPoiEntity, videoFileList, new DataSaveUtils.UploadCallback() {
|
||||
@Override
|
||||
public void run() {
|
||||
ZipUtil.zipFiles(videoFileList, fileZip, null);//压缩
|
||||
long zipTrueSize = ZipUtils.getZipTrueSize(fileZip.getAbsolutePath());
|
||||
if (zipTrueSize > 0) {
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (showPoiEntity == null) {
|
||||
showPoiEntity = new PoiEntity();
|
||||
}
|
||||
if (showPoiEntity.getTaskStatus() == 1 || showPoiEntity.getTaskStatus() == 2 || showPoiEntity.getTaskStatus() == 0 || showPoiEntity.getTaskStatus() == 5) {
|
||||
initPoiSaveLocal(true);
|
||||
} else {
|
||||
poiVideoUpload(showPoiEntity.getBodyId(), fileZip);
|
||||
Constant.isPresent = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fileZip.delete();
|
||||
ToastUtils.Message(getActivity(), "压缩文件失败,请重新提交");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
public void onStart() {
|
||||
dismissLoadingDialog();
|
||||
Constant.isPresent = false;
|
||||
getActivity().getSupportFragmentManager().popBackStack();//回退
|
||||
WaitDialog.show((AppCompatActivity) getActivity(), "任务正在后台上传中,请稍候...");
|
||||
WaitDialog.dismiss(3000);
|
||||
}
|
||||
}).start();
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
Constant.isPresent = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
|
||||
}
|
||||
});
|
||||
// fileZip = new File(Constant.PICTURE_FOLDER, "files" + ".zip");
|
||||
// new Thread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// ZipUtil.zipFiles(videoFileList, fileZip, null);//压缩
|
||||
// long zipTrueSize = ZipUtils.getZipTrueSize(fileZip.getAbsolutePath());
|
||||
// if (zipTrueSize > 0) {
|
||||
// if (getActivity() != null) {
|
||||
// getActivity().runOnUiThread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// if (showPoiEntity == null) {
|
||||
// showPoiEntity = new PoiEntity();
|
||||
// }
|
||||
// if (showPoiEntity.getTaskStatus() == 1 || showPoiEntity.getTaskStatus() == 2 || showPoiEntity.getTaskStatus() == 0 || showPoiEntity.getTaskStatus() == 5) {
|
||||
// initPoiSaveLocal(true);
|
||||
// } else {
|
||||
// poiVideoUpload(showPoiEntity.getBodyId(), fileZip);
|
||||
// Constant.isPresent = false;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// } else {
|
||||
// if (getActivity() != null) {
|
||||
// getActivity().runOnUiThread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// fileZip.delete();
|
||||
// ToastUtils.Message(getActivity(), "压缩文件失败,请重新提交");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }).start();
|
||||
} else {
|
||||
dismissLoadingDialog();
|
||||
ToastUtils.Message(getActivity(), "请录像");
|
||||
|
@ -12,6 +12,10 @@ public abstract class DialogCallback<T> extends JsonCallback<T> {
|
||||
@Override
|
||||
public void onSuccess(Response<T> response) { }
|
||||
|
||||
public DialogCallback() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DialogCallback( Class<T> tClass) {
|
||||
super(tClass);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
package com.navinfo.outdoor.http;
|
||||
|
||||
public class HttpInterface {
|
||||
public static final String IP = "http://172.23.138.133:9999/m4";//测试接口
|
||||
public static final String IP2 = "http://dtxbmaps.navinfo.com/dtxb/dev/m4";//测试接口-外网
|
||||
// public static final String IP = "http://172.23.138.133:9999/m4";//测试接口-IP
|
||||
public static final String IPm = "http://dtxbmaps.navinfo.com/dtxb/dev/m4";//开发接口-外网
|
||||
public static final String IP = "http://dtxbmaps.navinfo.com/dtxb/test/m4";//测试接口-外网
|
||||
public static final String IP1 = "http://dtxbmaps.navinfo.com/dtxb/m4";//正式接口
|
||||
public static final String USER_PATH = "/user/";//我的
|
||||
public static final String MSG_LIST_PATH = "/msgList/";//发现
|
||||
@ -136,6 +137,9 @@ public class HttpInterface {
|
||||
//dtxbmaps.navinfo.com/dtxb_test/m4/msgList/InfoPush/28/push?type=0
|
||||
public static String MESSAGE_INFO_PUSH = null;//消息通知
|
||||
public static String UPDATE_PHONE_NUM_URL = null;//消息通知
|
||||
public static String CREATE_UPLOAD_TASK = null;//创建断点续传任务
|
||||
public static String UPLOAD_SPLITE_TASK = null;//执行断点续传
|
||||
public static String UPLOAD_TASK_FINISH = null;//断点续传完成
|
||||
|
||||
public static String CONTACT_US = "";//联系我们
|
||||
public static String ABOUT_MAP = "";//关于 -关于地图寻宝
|
||||
@ -237,5 +241,8 @@ public class HttpInterface {
|
||||
COMPLETE = IP + TASK_PATH + "polygonTask/" + userId + "/complete";//面状任务结束领取
|
||||
SUBMIT_POLYGON_TASK = IP + TASK_PATH + "polygonTask/" + userId + "/submitPolygontask";//面状任务开始采集
|
||||
UPDATE_PHONE_NUM_URL = IP + UPDATE_PHONE_NUM_PATH.replace("{userId}", userId);// 修改手机号
|
||||
CREATE_UPLOAD_TASK = IP + TASK_PATH + "task/"+ userId+"/createUploadTask";// 创建断点续传任务
|
||||
UPLOAD_SPLITE_TASK = IP + TASK_PATH + "task/"+ userId+"/uploadSplitTask";// 执行断点续传
|
||||
UPLOAD_TASK_FINISH = IP + TASK_PATH + "task/"+ userId+"/uploadTaskFinish";// 断点续传完成
|
||||
}
|
||||
}
|
||||
|
339
app/src/main/java/com/navinfo/outdoor/util/DataSaveUtils.java
Normal file
339
app/src/main/java/com/navinfo/outdoor/util/DataSaveUtils.java
Normal file
@ -0,0 +1,339 @@
|
||||
package com.navinfo.outdoor.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.github.lazylibrary.util.FileUtils;
|
||||
import com.github.lazylibrary.util.MD5;
|
||||
import com.github.lazylibrary.util.ZipUtil;
|
||||
import com.hjq.permissions.OnPermissionCallback;
|
||||
import com.hjq.permissions.Permission;
|
||||
import com.hjq.permissions.XXPermissions;
|
||||
import com.kongzue.dialog.v3.TipDialog;
|
||||
import com.kongzue.dialog.v3.WaitDialog;
|
||||
import com.lzy.okgo.OkGo;
|
||||
import com.lzy.okgo.model.HttpParams;
|
||||
import com.lzy.okgo.model.Response;
|
||||
import com.navinfo.outdoor.api.Constant;
|
||||
import com.navinfo.outdoor.api.UserApplication;
|
||||
import com.navinfo.outdoor.bean.CommonRequestSend;
|
||||
import com.navinfo.outdoor.bean.CommonResponse;
|
||||
import com.navinfo.outdoor.bean.PoiSaveBean;
|
||||
import com.navinfo.outdoor.http.Callback;
|
||||
import com.navinfo.outdoor.http.DialogCallback;
|
||||
import com.navinfo.outdoor.http.HttpInterface;
|
||||
import com.navinfo.outdoor.http.OkGoBuilder;
|
||||
import com.navinfo.outdoor.room.InsertAndUpdateUtils;
|
||||
import com.navinfo.outdoor.room.PoiDatabase;
|
||||
import com.navinfo.outdoor.room.PoiEntity;
|
||||
import com.umeng.commonsdk.debug.UMLog;
|
||||
import com.umeng.umcrash.UMCrash;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.ObservableEmitter;
|
||||
import io.reactivex.ObservableOnSubscribe;
|
||||
import io.reactivex.ObservableSource;
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.SingleObserver;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.functions.Function;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
public class DataSaveUtils {
|
||||
private static DataSaveUtils instance;
|
||||
|
||||
public static DataSaveUtils getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new DataSaveUtils();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public interface UploadCallback {
|
||||
public void onStart();
|
||||
public void onFinish();
|
||||
public void onError();
|
||||
}
|
||||
|
||||
// 批量上传文件
|
||||
public void uploadFiles(Activity mContext, PoiEntity poiEntity, List<File> poiPicList, UploadCallback callback) {
|
||||
int auditId = poiEntity.getBodyId();
|
||||
File zipFile = new File(poiPicList.get(0).getParentFile(), auditId+".zip");
|
||||
Observable.create(new ObservableOnSubscribe<File>() {
|
||||
@Override
|
||||
public void subscribe(ObservableEmitter<File> emitter) throws Exception {
|
||||
if (!zipFile.exists()) {
|
||||
// 开始压缩文件
|
||||
ZipUtil.zipFiles(poiPicList, zipFile, "", null);
|
||||
}
|
||||
|
||||
emitter.onNext(zipFile);
|
||||
emitter.onComplete();
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.computation())
|
||||
// 切分数据,发送开始上传请求
|
||||
.map(new Function<File, Map<Integer, File>>() {
|
||||
@Override
|
||||
public Map<Integer, File> apply(File file) throws Exception {
|
||||
// 每次执行上传都会切分数据,因为都会执行第一步,向服务器请求需要上传的分包数据
|
||||
List<File> splitFiles = FileSpliteMergeUtils.splitFile(file, Constant.DEFAULT_CUT_SIZE);
|
||||
List<Long> chunkSizeList = new ArrayList<>();
|
||||
for (File f: splitFiles) {
|
||||
chunkSizeList.add(f.length());
|
||||
}
|
||||
CommonResponse<String> response = createUploadTask(mContext, auditId, file.length(), chunkSizeList);
|
||||
if (response!=null) {
|
||||
// 请求成功,获取需要上传的分包index
|
||||
String body = response.getBody();
|
||||
if (response.getCode() == 213) { // 该数据已经上传成功,自动切换该数据为已上传状态
|
||||
poiEntity.setTaskStatus(100);
|
||||
PoiDatabase.getInstance(mContext).getPoiDao().updatePoiEntity(poiEntity);
|
||||
ToastUtils.Message(mContext, "数据:"+poiEntity.getName()+"已成功上传!");
|
||||
}
|
||||
if (body==null||body.isEmpty()) {
|
||||
throw new Exception(response.getMessage());
|
||||
}
|
||||
String[] needUploadStrIndex = body.split(",");
|
||||
// 批量转换String为int
|
||||
int[] needUploadIndex = new int[needUploadStrIndex.length];
|
||||
for (int i = 0; i < needUploadStrIndex.length; i++) {
|
||||
needUploadIndex[i] = Integer.parseInt(needUploadStrIndex[i]);
|
||||
}
|
||||
// 根据返回的index,将需要上传的切分包数据流转到下一个流程
|
||||
Map<Integer, File> needUploadFileMap = new HashMap<>();
|
||||
for (int index: needUploadIndex) {
|
||||
if (index<splitFiles.size()) {
|
||||
needUploadFileMap.put(index, splitFiles.get(index));
|
||||
}
|
||||
}
|
||||
// 遍历已存在的切割文件,如果不需要上传,则删除该分包数据
|
||||
for (int i = 0; i < splitFiles.size(); i++) {
|
||||
if (!needUploadFileMap.keySet().contains(i)) {
|
||||
splitFiles.get(i).delete();
|
||||
}
|
||||
}
|
||||
return needUploadFileMap;
|
||||
} else {
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
})
|
||||
.flatMap(new Function<Map<Integer, File>, ObservableSource<Map.Entry<Integer, File>>>() {
|
||||
@Override
|
||||
public ObservableSource<Map.Entry<Integer, File>> apply(Map<Integer, File> filesMap) throws Exception {
|
||||
// 将每个切分的文件file作为发送者重新发送出去
|
||||
return Observable.fromIterable(filesMap.entrySet());
|
||||
}
|
||||
})
|
||||
.doOnNext(new Consumer<Map.Entry<Integer, File>>() {
|
||||
@Override
|
||||
public void accept(Map.Entry<Integer, File> fileEntry) throws Exception {
|
||||
// 执行上传流程
|
||||
CommonResponse response = uploadSplitTask(mContext, auditId, fileEntry.getKey(), fileEntry.getValue());
|
||||
if (response.getCode() != 200) {
|
||||
throw new Exception(response.getMessage());
|
||||
} else {
|
||||
UMLog.mutlInfo(3, "已上传分包"+fileEntry.getKey());
|
||||
// 上传成功,则删除该分包数据
|
||||
if (fileEntry.getValue().exists()) {
|
||||
fileEntry.getValue().delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.toList()
|
||||
.observeOn(Schedulers.io())
|
||||
// 调用执行成功的接口
|
||||
.doOnSuccess(new Consumer<List<Map.Entry<Integer, File>>>() {
|
||||
@Override
|
||||
public void accept(List<Map.Entry<Integer, File>> entries) throws Exception {
|
||||
// 最终成功,调用finish接口
|
||||
CommonResponse response = uploadTaskFinish(mContext, auditId);
|
||||
Message obtain1 = Message.obtain();
|
||||
obtain1.what = Constant.NEST_WORD_SUBMIT;
|
||||
if (response.getCode() == 200) { // 更新成功,再次更新本地数据库
|
||||
ToastUtils.Message(mContext, "分包数据上传完成!");
|
||||
poiEntity.setTaskStatus(100);
|
||||
PoiDatabase.getInstance(mContext).getPoiDao().updatePoiEntity(poiEntity);
|
||||
// 提醒用户数据上传完成
|
||||
obtain1.obj = "数据:" + poiEntity.getName() + " 上传成功";
|
||||
// 同时删除关联的照片文件和压缩包文件
|
||||
if (zipFile.exists()) {
|
||||
zipFile.delete();
|
||||
}
|
||||
if (poiPicList!=null&&!poiPicList.isEmpty()) {
|
||||
for (File picFile: poiPicList
|
||||
) {
|
||||
picFile.delete();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
obtain1.obj = "数据:" + poiEntity.getName() + " 上传失败";
|
||||
}
|
||||
EventBus.getDefault().post(obtain1);
|
||||
}
|
||||
})
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new SingleObserver<List<Map.Entry<Integer, File>>>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
callback.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(List<Map.Entry<Integer, File>> entries) {
|
||||
callback.onFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
ToastUtils.Message(mContext, e.getMessage());
|
||||
callback.onError();
|
||||
callback.onFinish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建分包上传任务
|
||||
* */
|
||||
private CommonResponse createUploadTask(Activity mContext, int auditId, long fileSize, List<Long> chunkSize) {
|
||||
HttpParams httpParams = new HttpParams();
|
||||
httpParams.put("auditId", auditId);
|
||||
httpParams.put("fileSize", fileSize);
|
||||
httpParams.put("chunkSize", list2Str(chunkSize));
|
||||
CommonRequestSend commonRequestSend = new CommonRequestSend<CommonResponse<String>>();
|
||||
CommonResponse response = commonRequestSend.getMethodCommonSync(mContext, HttpInterface.CREATE_UPLOAD_TASK, httpParams, Constant.DEFAULT_TIME_OUT, new CommonResponse<String>().getClass());
|
||||
if (response!=null) {
|
||||
if (response.getCode() == 200) {
|
||||
return response;
|
||||
} else {
|
||||
ToastUtils.Message(mContext, response.getMessage());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传分包数据
|
||||
* */
|
||||
private CommonResponse uploadSplitTask(Activity mContext, int auditId, int chunkIndex, File splitFile) {
|
||||
HttpParams httpParams = new HttpParams();
|
||||
httpParams.put("auditId", auditId);
|
||||
httpParams.put("chunkIndex", chunkIndex);
|
||||
httpParams.put("md5", MD5.md5sum(splitFile.getAbsolutePath()).toLowerCase());
|
||||
httpParams.put("file", splitFile);
|
||||
|
||||
// List<File> fileList = new ArrayList<>();
|
||||
// fileList.add(splitFile);
|
||||
CommonRequestSend commonRequestSend = new CommonRequestSend<CommonResponse<String>>();
|
||||
CommonResponse response = commonRequestSend.postMethodCommonSync(mContext, HttpInterface.UPLOAD_SPLITE_TASK, httpParams, Constant.DEFAULT_TIME_OUT, null, new CommonResponse<String>().getClass());
|
||||
if (response!=null) {
|
||||
if (response.getCode() == 200) {
|
||||
return response;
|
||||
} else {
|
||||
ToastUtils.Message(mContext, response.getMessage());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 分包数据上传完成
|
||||
* */
|
||||
private CommonResponse uploadTaskFinish(Activity mContext, int auditId) {
|
||||
HttpParams httpParams = new HttpParams();
|
||||
httpParams.put("auditId", auditId);
|
||||
CommonRequestSend commonRequestSend = new CommonRequestSend<CommonResponse<String>>();
|
||||
CommonResponse response = commonRequestSend.getMethodCommonSync(mContext, HttpInterface.UPLOAD_TASK_FINISH, httpParams, Constant.DEFAULT_TIME_OUT, new CommonResponse<String>().getClass());
|
||||
if (response!=null) {
|
||||
if (response.getCode() == 200) {
|
||||
return response;
|
||||
} else {
|
||||
ToastUtils.Message(mContext, response.getMessage());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Observable savePoiEntity(Context mContext, PoiEntity poiEntity) {
|
||||
return getPermission(mContext)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map(new Function() {
|
||||
@Override
|
||||
public PoiEntity apply(Object o) {
|
||||
return poiEntity;
|
||||
}
|
||||
})
|
||||
// 判断当前POI状态,根据状态处理随后的流程
|
||||
.map(new Function<PoiEntity, PoiEntity>() {
|
||||
@Override
|
||||
public PoiEntity apply(PoiEntity entity) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Observable getPermission(Context mContext) {
|
||||
return Observable.create(
|
||||
new ObservableOnSubscribe<Object>() {
|
||||
@Override
|
||||
public void subscribe(ObservableEmitter<Object> emitter) throws Exception {
|
||||
XXPermissions.with(mContext)
|
||||
//读写权限
|
||||
.permission(Permission.MANAGE_EXTERNAL_STORAGE)
|
||||
.request(new OnPermissionCallback() {
|
||||
@Override
|
||||
public void onGranted(List<String> permissions, boolean all) {
|
||||
if (all) {
|
||||
emitter.onNext("permission Ok");
|
||||
} else {
|
||||
emitter.onError(new Throwable("未获取文件访问权限,请确认!"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDenied(List<String> permissions, boolean never) {
|
||||
if (never) {
|
||||
emitter.onError(new Throwable("未获取文件访问权限,请确认!"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private String list2Str(List chunkSize) {
|
||||
StringBuilder result = new StringBuilder("");
|
||||
for (Object chunk: chunkSize) {
|
||||
result.append(chunk).append(",");
|
||||
}
|
||||
if (result.length()>0) {
|
||||
return result.substring(0, result.length()-1);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
package com.navinfo.outdoor.util
|
||||
|
||||
import android.util.Log
|
||||
import com.navinfo.outdoor.api.Constant
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.RandomAccessFile
|
||||
import java.lang.Exception
|
||||
|
||||
/**
|
||||
* @Author: LiaoZhongKai
|
||||
* @Date: 2021/7/28 19:42
|
||||
* @Description:
|
||||
*/
|
||||
object FileSpliteMergeUtils {
|
||||
const val TAG = "FileUtils"
|
||||
//默认切割文件的大小
|
||||
// private const val DEFAULT_CUT_SIZE: Long = 5*1024*1024//5MB
|
||||
private const val DEFAULT_CUT_SIZE: Long = Constant.DEFAULT_CUT_SIZE//5MB
|
||||
|
||||
/**
|
||||
* 分割文件
|
||||
* [sourceFile] 需要分割的源文件
|
||||
* [cutSize] 每个文件的大小
|
||||
* @return 分段文件集合
|
||||
*/
|
||||
@JvmStatic
|
||||
fun splitFile(sourceFile: File,cutSize: Long = DEFAULT_CUT_SIZE): List<File>{
|
||||
//分段片文件集合
|
||||
val singleFileList = mutableListOf<File>()
|
||||
|
||||
val totalLength = sourceFile.length()
|
||||
//分段数量
|
||||
val count = if(totalLength % cutSize == 0L) totalLength/cutSize else totalLength/cutSize +1
|
||||
Log.d(TAG,"split file count:$count")
|
||||
val mRandomAccFile = RandomAccessFile(sourceFile,"r")
|
||||
try {
|
||||
// val length = mRandomAccFile.length()
|
||||
// val singleSize = length/count//源文件分割后每个文件的大小
|
||||
var offSet = 0L
|
||||
|
||||
for (i in 0 until count){//最后一个文件单独处理,因为它的大小可能不等于singleSize
|
||||
val begin = offSet
|
||||
// 如果当前index对应的数据没有超过文件大小,则使用cutSize,否则使用文件实际剩余大小
|
||||
var end = begin + cutSize
|
||||
if (totalLength<end) {
|
||||
end = totalLength;
|
||||
}
|
||||
val file = createSingleFile(sourceFile,i)
|
||||
offSet = writeFile(mRandomAccFile,file,begin,end)
|
||||
singleFileList.add(file)
|
||||
}
|
||||
// if (length - offSet > 0){//最后一个文件
|
||||
// val file = createSingleFile(sourceFile,count-1)
|
||||
// writeFile(mRandomAccFile,file,offSet,length)
|
||||
// singleFileList.add(file)
|
||||
// }
|
||||
|
||||
}catch (e: FileNotFoundException){
|
||||
e.printStackTrace()
|
||||
}catch (e: IOException){
|
||||
e.printStackTrace()
|
||||
}finally {
|
||||
try {
|
||||
mRandomAccFile.close()
|
||||
}catch (e: IOException){
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
return singleFileList
|
||||
}
|
||||
|
||||
private fun createSingleFile(sourceFile: File,index: Long): File{
|
||||
val path = sourceFile.absolutePath.substringBeforeLast(".")
|
||||
// val suffix = sourceFile.name.substringAfterLast(".")
|
||||
val suffix = "tmp";
|
||||
val file = File("${path}_${index}.${suffix}")
|
||||
if (file.exists()){
|
||||
file.delete()
|
||||
}
|
||||
Log.d(TAG,"sourceFilePath:${sourceFile.absolutePath}")
|
||||
file.createNewFile()
|
||||
Log.d(TAG,"single file path:${file.absolutePath}")
|
||||
return file
|
||||
}
|
||||
|
||||
private fun writeFile(inFile: RandomAccessFile,single: File,begin: Long,end: Long): Long{
|
||||
var endPointer = 0L
|
||||
val out = RandomAccessFile(single,"rw")
|
||||
try {
|
||||
val byte = ByteArray(1024)
|
||||
var index = 0
|
||||
inFile.seek(begin)
|
||||
while (inFile.read(byte).also { index = it } != -1 && inFile.filePointer <= end){
|
||||
out.write(byte,0,index)
|
||||
}
|
||||
endPointer = inFile.filePointer
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
}finally {
|
||||
out.close()
|
||||
}
|
||||
return endPointer - 1024//减1024是为了避免分割文件时丢包
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并文件
|
||||
* [files] 需要合并的文件集合
|
||||
* [outputFilePath] 输出文件的路径 eg:D:/test
|
||||
* [outputFileName] 输出文件的名称 eg:crawler.json
|
||||
*/
|
||||
@JvmStatic
|
||||
fun mergeFile(files: List<File>,outputFilePath: String,outputFileName: String){
|
||||
|
||||
val parentFile = File(outputFilePath)
|
||||
val targetFile = File(outputFilePath+File.separator+outputFileName)
|
||||
if (!parentFile.exists()){
|
||||
parentFile.mkdirs()
|
||||
}
|
||||
if (!targetFile.exists()){
|
||||
targetFile.createNewFile()
|
||||
}
|
||||
|
||||
val outRaf = RandomAccessFile(targetFile,"rw")
|
||||
try {
|
||||
files.forEach { file ->
|
||||
val reader = RandomAccessFile(file,"r")
|
||||
val byte = ByteArray(1024)
|
||||
var index = 0
|
||||
while (reader.read(byte).also { index = it } != -1){
|
||||
outRaf.write(byte,0,index)
|
||||
}
|
||||
}
|
||||
files.forEach {
|
||||
if (it.exists()){
|
||||
it.delete()
|
||||
}
|
||||
}
|
||||
Log.d(TAG,"merge output file path:${targetFile.absolutePath}")
|
||||
}catch (e: IOException){
|
||||
e.printStackTrace()
|
||||
}catch (e: FileNotFoundException){
|
||||
e.printStackTrace()
|
||||
}
|
||||
finally {
|
||||
outRaf.close()
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import com.navinfo.outdoor.room.ChargingPileEntity;
|
||||
import com.navinfo.outdoor.room.InsertAndUpdateUtils;
|
||||
import com.navinfo.outdoor.room.PoiDatabase;
|
||||
import com.navinfo.outdoor.room.PoiEntity;
|
||||
import com.umeng.commonsdk.debug.UMLog;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
@ -256,24 +257,42 @@ public class PoiSaveUtils {
|
||||
bInt++;
|
||||
return;
|
||||
}
|
||||
File fileZip = new File(Constant.PICTURE_FOLDER, "files" + ".zip");
|
||||
ZipUtil.zipFiles(videoFileList, fileZip, null);
|
||||
photoFile.add(fileZip);
|
||||
// 需要上传的文件都存在,开始调用分片上传接口上传附件数据
|
||||
DataSaveUtils.getInstance().uploadFiles(mContext, poiEntity, videoFileList, new DataSaveUtils.UploadCallback() {
|
||||
@Override
|
||||
public void onStart() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
anInt++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
// 上传失败
|
||||
bInt++;
|
||||
}
|
||||
});
|
||||
// File fileZip = new File(Constant.PICTURE_FOLDER, "files" + ".zip");
|
||||
// ZipUtil.zipFiles(videoFileList, fileZip, null);
|
||||
// photoFile.add(fileZip);
|
||||
} else {
|
||||
bInt++;
|
||||
return;
|
||||
}
|
||||
if (photoFile.size() > 0) {
|
||||
long zipTrueSize = ZipUtils.getZipTrueSize(photoFile.get(0).getAbsolutePath());
|
||||
if (zipTrueSize > 0) {
|
||||
initList(HttpInterface.POI_VIDEO_UPLOAD_PIC, photoFile, poiEntity);
|
||||
} else {
|
||||
for (int i = 0; i < photoFile.size(); i++) {
|
||||
photoFile.get(i).delete();
|
||||
}
|
||||
bInt++;
|
||||
}
|
||||
}
|
||||
// if (photoFile.size() > 0) {
|
||||
// long zipTrueSize = ZipUtils.getZipTrueSize(photoFile.get(0).getAbsolutePath());
|
||||
// if (zipTrueSize > 0) {
|
||||
// initList(HttpInterface.POI_VIDEO_UPLOAD_PIC, photoFile, poiEntity);
|
||||
// } else {
|
||||
// for (int i = 0; i < photoFile.size(); i++) {
|
||||
// photoFile.get(i).delete();
|
||||
// }
|
||||
// bInt++;
|
||||
// }
|
||||
// }
|
||||
} else if (poiEntity.getType() == 4) {
|
||||
List<File> videoFileList = AWMp4ParserHelper.getInstance().getFileListByUUID(poiEntity.getId());
|
||||
if (videoFileList != null && !videoFileList.isEmpty()) {
|
||||
@ -282,27 +301,48 @@ public class PoiSaveUtils {
|
||||
bInt++;
|
||||
return;
|
||||
}
|
||||
File fileZip = new File(Constant.PICTURE_FOLDER, "files" + ".zip");
|
||||
ZipUtil.zipFiles(videoFileList, fileZip, null);
|
||||
photoFile.add(fileZip);
|
||||
// 需要上传的文件都存在,开始调用分片上传接口上传附件数据
|
||||
DataSaveUtils.getInstance().uploadFiles(mContext, poiEntity, videoFileList, new DataSaveUtils.UploadCallback() {
|
||||
@Override
|
||||
public void onStart() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
anInt++;
|
||||
Log.d("TAGSS", "uploadPoiNet: 成功" + anInt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
// 上传失败
|
||||
bInt++;
|
||||
Log.d("TAGSS", poiEntity.getBodyId()+"uploadPoiNet: 失败" + bInt);
|
||||
UMLog.aq(1, poiEntity.getBodyId()+"uploadPoiNet: 失败", "文件上传失败");
|
||||
}
|
||||
});
|
||||
// File fileZip = new File(Constant.PICTURE_FOLDER, "files" + ".zip");
|
||||
// ZipUtil.zipFiles(videoFileList, fileZip, null);
|
||||
// photoFile.add(fileZip);
|
||||
} else {
|
||||
Log.d("TAGSS", "videoFileList: 失败" + bInt);
|
||||
bInt++;
|
||||
return;
|
||||
}
|
||||
if (photoFile.size() > 0) {
|
||||
long zipTrueSize = ZipUtils.getZipTrueSize(photoFile.get(0).getAbsolutePath());
|
||||
if (zipTrueSize > 0) {
|
||||
initList(HttpInterface.ROAD_TASK_UPLOAD_PIC, photoFile, poiEntity);
|
||||
} else {
|
||||
Log.d("TAGSS", "photoFile: 失败" + bInt);
|
||||
for (int i = 0; i < photoFile.size(); i++) {
|
||||
photoFile.get(i).delete();
|
||||
}
|
||||
bInt++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if (photoFile.size() > 0) {
|
||||
// long zipTrueSize = ZipUtils.getZipTrueSize(photoFile.get(0).getAbsolutePath());
|
||||
// if (zipTrueSize > 0) {
|
||||
// initList(HttpInterface.ROAD_TASK_UPLOAD_PIC, photoFile, poiEntity);
|
||||
// } else {
|
||||
// Log.d("TAGSS", "photoFile: 失败" + bInt);
|
||||
// for (int i = 0; i < photoFile.size(); i++) {
|
||||
// photoFile.get(i).delete();
|
||||
// }
|
||||
// bInt++;
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
} else if (poiEntity.getType() == 5) {
|
||||
initList(HttpInterface.OTHER_TASK_UPLOAD_PIC, photoFile, poiEntity);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.anko_version = '0.10.1'//扩展库版本
|
||||
ext.kotlin_version = '1.5.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
@ -19,8 +20,8 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:4.0.0"
|
||||
|
||||
|
||||
//对kotlin支持
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
Loading…
x
Reference in New Issue
Block a user