├── .gitignore ├── OkHttpLibSDK ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── xingen │ │ └── okhttplib │ │ ├── NetClient.java │ │ ├── common │ │ ├── listener │ │ │ ├── FileBlockResponseListener.java │ │ │ ├── ProgressListener.java │ │ │ ├── ResponseListener.java │ │ │ └── ResultListener.java │ │ └── utils │ │ │ ├── FileUtils.java │ │ │ ├── LogUtils.java │ │ │ └── MD5Utils.java │ │ ├── config │ │ └── NetConfig.java │ │ └── internal │ │ ├── block │ │ └── FileBlockManager.java │ │ ├── db │ │ ├── DBClient.java │ │ ├── bean │ │ │ ├── FileItemBean.java │ │ │ └── FileTaskBean.java │ │ ├── dao │ │ │ ├── BaseDao.java │ │ │ ├── FileItemImp.java │ │ │ └── FileTaskImp.java │ │ ├── sqlite │ │ │ ├── DatabaseConstants.java │ │ │ └── UploadFileTaskDatabase.java │ │ └── utils │ │ │ └── DBUtils.java │ │ ├── dispatch │ │ ├── Dispatcher.java │ │ └── ThreadDispatcher.java │ │ ├── error │ │ └── CommonError.java │ │ ├── execute │ │ ├── NetExecutor.java │ │ └── NetExecutorImp.java │ │ ├── executor │ │ └── MainExecutor.java │ │ ├── json │ │ ├── parser │ │ │ ├── OkHttpBaseParser.java │ │ │ └── OkHttpJsonParser.java │ │ └── utils │ │ │ ├── GsonUtils.java │ │ │ └── JsonUtils.java │ │ ├── okhttp │ │ ├── BlockBody.java │ │ ├── FileRequestBody.java │ │ ├── HeaderInterceptor.java │ │ ├── HttpLoggingInterceptor.java │ │ ├── OkHttpProvider.java │ │ └── RequestBodyUtils.java │ │ ├── request │ │ ├── BaseRequest.java │ │ ├── FormRequest.java │ │ ├── GsonRequest.java │ │ ├── MultiBlockRequest.java │ │ └── SingleFileRequest.java │ │ ├── response │ │ └── ResponseResult.java │ │ └── thread │ │ ├── BaseThread.java │ │ ├── CacheThread.java │ │ ├── CalculateThread.java │ │ ├── NetWorkThread.java │ │ ├── ThreadManger.java │ │ └── UploadBlockThread.java │ └── res │ └── values │ └── strings.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── xingen │ │ └── okhttplibtest │ │ ├── BaseApplication.java │ │ ├── MainActivity.java │ │ └── bean │ │ ├── BlockBean.java │ │ ├── FileBean.java │ │ ├── HttpResult.java │ │ ├── Movie.java │ │ ├── MovieList.java │ │ └── TokenBean.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | 11 | .idea 12 | -------------------------------------------------------------------------------- /OkHttpLibSDK/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /OkHttpLibSDK/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.novoda.bintray-release'//添加 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | minSdkVersion 14 7 | targetSdkVersion 26 8 | versionCode 1 9 | versionName "1.0" 10 | multiDexEnabled true 11 | } 12 | buildTypes { 13 | release { 14 | minifyEnabled false 15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 16 | } 17 | } 18 | lintOptions { 19 | abortOnError false 20 | } 21 | 22 | } 23 | 24 | dependencies { 25 | compile 'com.android.support:appcompat-v7:26.1.0' 26 | //OkHttp的依赖 27 | compile 'com.squareup.okhttp3:okhttp:3.8.0' 28 | //gson解析库 29 | compile 'com.google.code.gson:gson:2.2.4' 30 | } 31 | 32 | //添加 33 | publish { 34 | userOrg = 'hexingen'//bintray.com用户名 35 | groupId = 'com.xingen'//jcenter上的路径 36 | artifactId = 'okhttplib'//项目名称 37 | publishVersion = '1.0.0'//版本号 38 | desc = 'Oh hi, this is a nice description for a project, right?'//描述,不重要 39 | website = 'https://github.com/13767004362/OkHttpLib'//网站,github上的地址 40 | } -------------------------------------------------------------------------------- /OkHttpLibSDK/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/NetClient.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib; 2 | 3 | import android.content.Context; 4 | 5 | import com.xingen.okhttplib.common.listener.FileBlockResponseListener; 6 | import com.xingen.okhttplib.common.listener.ProgressListener; 7 | import com.xingen.okhttplib.common.listener.ResponseListener; 8 | import com.xingen.okhttplib.config.NetConfig; 9 | import com.xingen.okhttplib.internal.db.DBClient; 10 | import com.xingen.okhttplib.internal.execute.NetExecutor; 11 | import com.xingen.okhttplib.internal.execute.NetExecutorImp; 12 | import com.xingen.okhttplib.internal.executor.MainExecutor; 13 | import com.xingen.okhttplib.internal.json.utils.GsonUtils; 14 | import com.xingen.okhttplib.internal.okhttp.OkHttpProvider; 15 | import com.xingen.okhttplib.internal.request.BaseRequest; 16 | import com.xingen.okhttplib.internal.request.FormRequest; 17 | import com.xingen.okhttplib.internal.request.GsonRequest; 18 | import com.xingen.okhttplib.internal.request.MultiBlockRequest; 19 | import com.xingen.okhttplib.internal.request.SingleFileRequest; 20 | import com.xingen.okhttplib.internal.thread.ThreadManger; 21 | 22 | import org.json.JSONObject; 23 | 24 | import java.util.Map; 25 | 26 | import okhttp3.OkHttpClient; 27 | 28 | /** 29 | * Created by ${xinGen} on 2018/1/19. 30 | */ 31 | 32 | public class NetClient { 33 | private static NetClient instance; 34 | private ThreadManger threadManger; 35 | private NetExecutor netExecutor; 36 | private MainExecutor mainExecutor; 37 | private OkHttpClient okHttpClient; 38 | private DBClient dbClient; 39 | static { 40 | instance = new NetClient(); 41 | } 42 | private NetClient() { 43 | this.mainExecutor = new MainExecutor(); 44 | this.netExecutor = new NetExecutorImp(this.mainExecutor); 45 | this.threadManger = ThreadManger.getInstance(); 46 | this.dbClient=DBClient.getInstance(); 47 | } 48 | public static NetClient getInstance() { 49 | return instance; 50 | } 51 | public void initSDK(Context context) { 52 | initSDK(context,null); 53 | } 54 | public synchronized void initSDK(Context context,NetConfig netConfig) { 55 | if (okHttpClient == null) { 56 | this.okHttpClient = OkHttpProvider.createOkHttpClient(netConfig); 57 | this.netExecutor.setOkHttpClient(this.okHttpClient); 58 | this.dbClient.init(context); 59 | } 60 | } 61 | 62 | /** 63 | * 64 | * @param url 65 | * @param object 66 | * @param headers 67 | * @param requestResultListener 68 | * @param 69 | * @return 70 | */ 71 | public GsonRequest executeJsonRequest(String url, Object object, Map headers, ResponseListener requestResultListener) { 72 | GsonRequest request = new GsonRequest(url, GsonUtils.toJson(object), headers, requestResultListener); 73 | this.threadManger.addRequest(request); 74 | return request; 75 | } 76 | /** 77 | * Json上传 78 | * 79 | * @param url 80 | * @param jsonObject 81 | * @param requestResultListener 82 | * @param 83 | * @return 84 | */ 85 | public GsonRequest executeJsonRequest(String url, JSONObject jsonObject, ResponseListener requestResultListener) { 86 | return executeJsonRequest(url,jsonObject,null,requestResultListener); 87 | } 88 | /** 89 | * Json上传 90 | * 91 | * @param url 92 | * @param jsonObject 93 | * @param headers 94 | * @param requestResultListener 95 | * @param 96 | * @return 97 | */ 98 | public GsonRequest executeJsonRequest(String url, JSONObject jsonObject, Map headers, ResponseListener requestResultListener) { 99 | GsonRequest request = new GsonRequest(url, jsonObject, headers, requestResultListener); 100 | this.threadManger.addRequest(request); 101 | return request; 102 | } 103 | /** 104 | * form表单上传 105 | * @param url 106 | * @param body 107 | * @param requestResultListener 108 | * @param 109 | * @return 110 | */ 111 | public FormRequest executeFormRequest(String url, Map body, ResponseListener requestResultListener) { 112 | return executeFormRequest(url,body,null,requestResultListener); 113 | } 114 | /** 115 | * form表单上传 116 | * @param url 117 | * @param body 118 | * @param headers 119 | * @param requestResultListener 120 | * @param 121 | * @return 122 | */ 123 | public FormRequest executeFormRequest(String url, Map body, Map headers, ResponseListener requestResultListener) { 124 | FormRequest request = new FormRequest<>(url, body, headers, requestResultListener); 125 | this.threadManger.addRequest(request); 126 | return request; 127 | } 128 | 129 | /** 130 | * 单文件上传 131 | * @param url 132 | * @param filePath 133 | * @param progressListener 134 | * @param requestResultListener 135 | * @param 136 | * @return 137 | */ 138 | public SingleFileRequest executeSingleFileRequest(String url, String filePath, ProgressListener progressListener, ResponseListener requestResultListener) { 139 | return executeSingleFileRequest(url,filePath,null,progressListener,requestResultListener); 140 | } 141 | /** 142 | * 单文件上传 143 | * 文件和headers 144 | * @param 145 | * @return 146 | */ 147 | public SingleFileRequest executeSingleFileRequest(String url, String filePath, Map headers, ProgressListener progressListener, ResponseListener requestResultListener) { 148 | SingleFileRequest request = new SingleFileRequest<>(url, filePath, headers,progressListener, requestResultListener); 149 | this.threadManger.addRequest(request); 150 | return request; 151 | } 152 | 153 | /** 154 | * 超大文件分块上传 155 | * 156 | * @param url 157 | * @param filePath 158 | * @param progressListener 159 | * @param requestResultListener 160 | * @param 161 | * @return 162 | */ 163 | public MultiBlockRequest executeMultiBlockRequest(String url,String filePath, ProgressListener progressListener, FileBlockResponseListener requestResultListener) { 164 | MultiBlockRequest request=new MultiBlockRequest<>(url,filePath,progressListener,requestResultListener); 165 | this.threadManger.addMultiBlockRequest(request); 166 | return null; 167 | } 168 | 169 | /** 170 | * 取消请求 171 | * @param url 172 | */ 173 | public void cancelRequests(String url) { 174 | this.threadManger.removeRequest(url); 175 | } 176 | /** 177 | * 取消请求 178 | * @param baseRequest 179 | */ 180 | public void cancelRequests(BaseRequest baseRequest){ 181 | if (baseRequest!=null){ 182 | baseRequest.cancel(); 183 | cancelRequests(baseRequest.getUrl()); 184 | } 185 | } 186 | /** 187 | * 取消请求 188 | * @param multiBlockRequest 189 | */ 190 | public void cancelRequests(MultiBlockRequest multiBlockRequest){ 191 | if (multiBlockRequest!=null){ 192 | multiBlockRequest.cancel(); 193 | cancelRequests(multiBlockRequest.getUrl()); 194 | } 195 | } 196 | 197 | /** 198 | * 慎重调用,在特殊情况下,例如:进程销毁 199 | */ 200 | public void destroy() { 201 | this.threadManger.destroy(); 202 | this.dbClient.closeDataBase(); 203 | } 204 | public NetExecutor getNetExecutor() { 205 | return this.netExecutor; 206 | } 207 | public MainExecutor getMainExecutor() { 208 | return this.mainExecutor; 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/common/listener/FileBlockResponseListener.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.common.listener; 2 | 3 | /** 4 | * Created by ${xinGen} on 2018/1/31. 5 | */ 6 | 7 | public abstract class FileBlockResponseListener extends ResponseListener { 8 | /** 9 | * 文件已经上传 10 | * @param filePath 11 | * @param t 12 | */ 13 | public abstract void fileAlreadyUpload(String filePath,T t); 14 | } 15 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/common/listener/ProgressListener.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.common.listener; 2 | 3 | /** 4 | * Created by ${xinGen} on 2018/1/22. 5 | */ 6 | 7 | public interface ProgressListener { 8 | /** 9 | * 上传进度的百分之几 10 | * @param progress 11 | */ 12 | void progress(int progress); 13 | } 14 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/common/listener/ResponseListener.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.common.listener; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonSyntaxException; 5 | import com.xingen.okhttplib.internal.error.CommonError; 6 | import com.xingen.okhttplib.internal.json.parser.OkHttpBaseParser; 7 | import com.xingen.okhttplib.internal.json.utils.GsonUtils; 8 | 9 | import java.io.IOException; 10 | import java.lang.reflect.Type; 11 | 12 | import okhttp3.Response; 13 | 14 | /** 15 | * Created by ${xinGen} on 2018/1/29. 16 | */ 17 | 18 | public abstract class ResponseListener implements ResultListener, OkHttpBaseParser { 19 | private Type type; 20 | private Gson gson; 21 | public ResponseListener() { 22 | this.type = GsonUtils.getSuperclassTypeParameter(getClass()); 23 | this.gson = new Gson(); 24 | } 25 | @Override 26 | public T parser(Response response) throws IOException ,NullPointerException{ 27 | String s = response.body().string(); 28 | return parser(s); 29 | } 30 | public T parser(String s) { 31 | try { 32 | T t = GsonUtils.toBean(gson, s, type); 33 | return t; 34 | } catch (JsonSyntaxException e) { 35 | throw new CommonError(CommonError.State.error_parser,e.getMessage()); 36 | }catch (Exception e){ 37 | throw new CommonError(CommonError.State.error_unknown,e.getMessage()); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/common/listener/ResultListener.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.common.listener; 2 | 3 | /** 4 | * Created by ${xinGen} on 2018/1/19. 5 | * 6 | * 请求结果的回调接口 7 | */ 8 | 9 | public interface ResultListener { 10 | void error(Exception e); 11 | 12 | void success(T t); 13 | } 14 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/common/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.common.utils; 2 | 3 | import java.io.File; 4 | import java.io.RandomAccessFile; 5 | 6 | /** 7 | * Created by ${xinGen} on 2018/1/22. 8 | */ 9 | 10 | public class FileUtils { 11 | 12 | 13 | /** 14 | * 每个块的长度,这里设置10M 15 | */ 16 | public static final int CHUNK_LENGTH = 1 * 1024 * 1024; 17 | 18 | /** 19 | * 从路径中获取文件名 20 | * 21 | * @param filePath 22 | * @return 23 | */ 24 | public static String getFileName(String filePath) { 25 | return filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length()); 26 | } 27 | 28 | /** 29 | * 从指定位置获取指定长度的byte 30 | * 31 | * @param offset 起始位置 32 | * @param file 上传的文件 33 | * @param blockSize 读取的块的长度 34 | * @return 35 | */ 36 | public static byte[] getBlock(long offset, File file, int blockSize) { 37 | byte[] result = new byte[blockSize]; 38 | RandomAccessFile randomAccessFile = null; 39 | try { 40 | randomAccessFile = new RandomAccessFile(file, "r"); 41 | randomAccessFile.seek(offset); 42 | int readLength = randomAccessFile.read(result); 43 | if (readLength == -1) { 44 | return null; 45 | } else if (readLength == blockSize) { 46 | return result; 47 | } else { 48 | byte[] tmpByte = new byte[readLength]; 49 | System.arraycopy(result, 0, tmpByte, 0, readLength); 50 | return tmpByte; 51 | } 52 | } catch (Exception e) { 53 | e.printStackTrace(); 54 | } finally { 55 | try { 56 | if (randomAccessFile != null) { 57 | randomAccessFile.close(); 58 | } 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | return null; 64 | } 65 | 66 | ; 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/common/utils/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.common.utils; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/20. 7 | * 8 | * log日志工具类 9 | */ 10 | 11 | public class LogUtils { 12 | 13 | public static final int LEVEL_NOTHING=-1; 14 | public static final int LEVEL_I=1; 15 | public static final int LEVEL_D=2; 16 | public static final int LEVEL_E=3; 17 | 18 | public static int current_level= LEVEL_I; 19 | 20 | public static void i(String tag,String log){ 21 | if (current_level>=LEVEL_I){ 22 | Log.i(tag,log); 23 | } 24 | } 25 | public static void d(String tag,String log){ 26 | if (current_level>=LEVEL_D){ 27 | Log.d(tag,log); 28 | } 29 | } 30 | public static void e(String tag,String log){ 31 | if (current_level>= LEVEL_E){ 32 | Log.e(tag,log); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/common/utils/MD5Utils.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.common.utils; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileNotFoundException; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.RandomAccessFile; 11 | import java.math.BigInteger; 12 | import java.security.DigestInputStream; 13 | import java.security.MessageDigest; 14 | import java.security.NoSuchAlgorithmException; 15 | 16 | /** 17 | * Created by ${xinGen} on 2018/1/31. 18 | */ 19 | 20 | public class MD5Utils { 21 | private static final String TAG=MD5Utils.class.getSimpleName(); 22 | /** 23 | * 24 | * 通过DigestInputStream ,获取消息摘要的方式。 25 | * 26 | * 对大文件,采用DigestInputStream,以防直接获取文件数组全部读取内存中。 27 | * 28 | * @param filePath 29 | * @return 30 | */ 31 | public static String borrowDigestInputStream(String filePath) { 32 | FileInputStream fileInputStream = null; 33 | DigestInputStream digestInputStream = null; 34 | try { 35 | // 缓冲区大小(这个可以抽出一个参数) 36 | int bufferSize = 256 * 1024; 37 | MessageDigest messageDigest = MessageDigest.getInstance("MD5"); 38 | fileInputStream = new FileInputStream(new File(filePath)); 39 | digestInputStream = new DigestInputStream(fileInputStream, messageDigest); 40 | // read的过程中进行MD5处理,直到读完文件 41 | byte[] buffer = new byte[bufferSize]; 42 | while (digestInputStream.read(buffer) > 0) ; 43 | // 获取最终的MessageDigest 44 | messageDigest = digestInputStream.getMessageDigest(); 45 | // 拿到结果,也是字节数组,包含16个元素 46 | byte[] resultByteArray = messageDigest.digest(); 47 | // 同样,把字节数组转换成字符串 48 | return byteArrayToString(resultByteArray); 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | return null; 52 | } finally { 53 | try { 54 | digestInputStream.close(); 55 | } catch (Exception e) { 56 | } 57 | try { 58 | fileInputStream.close(); 59 | } catch (Exception e) { 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * 66 | * 将字节数组换成成16进制的字符串 67 | * 68 | * @param byteArray 69 | * @return 70 | */ 71 | public static String byteArrayToString(byte[] byteArray) { 72 | // 首先初始化一个字符数组,用来存放每个16进制字符 73 | char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 74 | // new一个字符数组,这个就是用来组成结果字符串的(解释一下:一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方)) 75 | 76 | char[] resultCharArray = new char[byteArray.length * 2]; 77 | // 遍历字节数组,通过位运算(位运算效率高),转换成字符放到字符数组中去 78 | int index = 0; 79 | for (byte b : byteArray) { 80 | resultCharArray[index++] = hexDigits[b >>> 4 & 0xf]; 81 | resultCharArray[index++] = hexDigits[b & 0xf]; 82 | } 83 | // 字符数组组合成字符串返回 84 | return new String(resultCharArray); 85 | } 86 | 87 | 88 | 89 | public static boolean checkMD5(String md5, File updateFile) { 90 | if (TextUtils.isEmpty(md5) || updateFile == null) { 91 | return false; 92 | } 93 | String calculatedDigest = borrowFileInputStream(updateFile.getAbsolutePath()); 94 | if (calculatedDigest == null) { 95 | return false; 96 | } 97 | return calculatedDigest.equalsIgnoreCase(md5); 98 | } 99 | 100 | /** 101 | * 102 | * FileInputStream字节流方式方式获取文件md5值 103 | * 104 | * 105 | * 106 | * @param filePath 107 | * @return 108 | */ 109 | public static String borrowFileInputStream(String filePath) { 110 | File updateFile=new File(filePath); 111 | MessageDigest digest; 112 | try { 113 | digest = MessageDigest.getInstance("MD5"); 114 | } catch (NoSuchAlgorithmException e) { 115 | e.printStackTrace(); 116 | return null; 117 | } 118 | 119 | InputStream is; 120 | try { 121 | is = new FileInputStream(updateFile); 122 | } catch (FileNotFoundException e) { 123 | return null; 124 | } 125 | 126 | byte[] buffer = new byte[8192]; 127 | int read; 128 | try { 129 | while ((read = is.read(buffer)) > 0) { 130 | digest.update(buffer, 0, read); 131 | } 132 | byte[] md5sum = digest.digest(); 133 | BigInteger bigInt = new BigInteger(1, md5sum); 134 | String output = bigInt.toString(16); 135 | // Fill to 32 chars 136 | output = String.format("%32s", output).replace(' ', '0'); 137 | return output; 138 | } catch (IOException e) { 139 | throw new RuntimeException("Unable to process file for MD5", e); 140 | } finally { 141 | try { 142 | is.close(); 143 | } catch (IOException e) { 144 | e.printStackTrace(); 145 | } 146 | } 147 | } 148 | 149 | /** 150 | * 151 | * RandomAccessFile 获取文件的MD5值 152 | * 153 | * @param filePath 文件路径 154 | * @return md5 155 | */ 156 | public static String borrowRandomAccessFile(String filePath) { 157 | File file= new File(filePath); 158 | MessageDigest messageDigest; 159 | RandomAccessFile randomAccessFile = null; 160 | try { 161 | messageDigest = MessageDigest.getInstance("MD5"); 162 | if (file == null) { 163 | return ""; 164 | } 165 | if (!file.exists()) { 166 | return ""; 167 | } 168 | randomAccessFile=new RandomAccessFile(file,"r"); 169 | byte[] bytes=new byte[1024*1024*10]; 170 | int len=0; 171 | while ((len=randomAccessFile.read(bytes))!=-1){ 172 | messageDigest.update(bytes,0, len); 173 | } 174 | BigInteger bigInt = new BigInteger(1, messageDigest.digest()); 175 | String md5 = bigInt.toString(16); 176 | while (md5.length() < 32) { 177 | md5 = "0" + md5; 178 | } 179 | return md5; 180 | } catch (NoSuchAlgorithmException e) { 181 | e.printStackTrace(); 182 | } catch (FileNotFoundException e) { 183 | e.printStackTrace(); 184 | } catch (IOException e) { 185 | 186 | e.printStackTrace(); 187 | } finally { 188 | try { 189 | if (randomAccessFile != null) { 190 | randomAccessFile.close(); 191 | randomAccessFile = null; 192 | } 193 | } catch (IOException e) { 194 | e.printStackTrace(); 195 | } 196 | } 197 | return ""; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/config/NetConfig.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.config; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Created by ${xinGen} on 2018/1/19. 8 | * 9 | * 网络配置类 10 | * 11 | */ 12 | 13 | public class NetConfig { 14 | /** 15 | * 是否开启 log 16 | */ 17 | private boolean isLog; 18 | /** 19 | * 通用表头 20 | */ 21 | private Map commonHeaders; 22 | private NetConfig(){ 23 | this.commonHeaders=new HashMap<>(); 24 | } 25 | public boolean isLog() { 26 | return isLog; 27 | } 28 | public void setLog(boolean log) { 29 | isLog = log; 30 | } 31 | public void addCommonHeader(String key,String values){ 32 | this.commonHeaders.put(key,values); 33 | } 34 | public Map getCommonHeaders() { 35 | return commonHeaders; 36 | } 37 | public void setCommonHeaders(Map commonHeaders) { 38 | this.commonHeaders = commonHeaders; 39 | } 40 | public static class Builder{ 41 | private NetConfig netConfig; 42 | public Builder(){ 43 | this.netConfig=new NetConfig(); 44 | } 45 | public Builder setLog(boolean log) { 46 | this.netConfig. isLog = log; 47 | return this; 48 | } 49 | public Builder addCommonHeader(String key,String values){ 50 | this.netConfig.commonHeaders.put(key,values); 51 | return this; 52 | } 53 | public NetConfig builder(){ 54 | return this.netConfig; 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/block/FileBlockManager.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.block; 2 | 3 | import android.util.Log; 4 | 5 | import com.xingen.okhttplib.NetClient; 6 | import com.xingen.okhttplib.internal.db.DBClient; 7 | import com.xingen.okhttplib.internal.db.bean.FileItemBean; 8 | import com.xingen.okhttplib.internal.db.bean.FileTaskBean; 9 | import com.xingen.okhttplib.internal.db.sqlite.DatabaseConstants; 10 | import com.xingen.okhttplib.internal.executor.MainExecutor; 11 | import com.xingen.okhttplib.internal.request.MultiBlockRequest; 12 | import com.xingen.okhttplib.internal.thread.ThreadManger; 13 | import com.xingen.okhttplib.internal.thread.UploadBlockThread; 14 | 15 | import java.util.List; 16 | import java.util.concurrent.ExecutorService; 17 | 18 | /** 19 | * Created by ${xinGen} on 2018/1/31. 20 | * 管理类: 21 | * 22 | */ 23 | 24 | public class FileBlockManager { 25 | private static final String TAG = FileBlockManager.class.getSimpleName(); 26 | /** 27 | * 默认三个线程 28 | */ 29 | private final int default_thread_size = 3; 30 | /** 31 | * 请求中 32 | */ 33 | private MultiBlockRequest multiBlockRequest; 34 | /** 35 | * 数据库管理 36 | */ 37 | private DBClient dbClient; 38 | /** 39 | * 线程池管理 40 | */ 41 | private ExecutorService uploadThreadPool; 42 | /** 43 | * 主线程管理 44 | */ 45 | private MainExecutor mainExecutor; 46 | /** 47 | * 计算线程 48 | */ 49 | private Thread calculateThread; 50 | /** 51 | * 上传文件线程的个数 52 | */ 53 | private int threadSize; 54 | 55 | public FileBlockManager(MultiBlockRequest multiBlockRequest) { 56 | this.multiBlockRequest = multiBlockRequest; 57 | this.dbClient = DBClient.getInstance(); 58 | this.mainExecutor = NetClient.getInstance().getMainExecutor(); 59 | this.threadSize = default_thread_size; 60 | } 61 | public void startUpLoad() { 62 | this.mainExecutor.execute(new Runnable() { 63 | @Override 64 | public void run() { 65 | startUploadThread(); 66 | } 67 | }); 68 | } 69 | /** 70 | * 开启上传任务 71 | */ 72 | private void startUploadThread() { 73 | List fileItemList = multiBlockRequest.getFileItemList(); 74 | if (fileItemList != null && fileItemList.size() > 0) { 75 | if (isCancel()) { 76 | return; 77 | } 78 | uploadThreadPool = ThreadManger.getInstance().createThreadPool(fileItemList.size()); 79 | for (int i = 0; i < fileItemList.size(); ++i) { 80 | FileItemBean fileItemBean = fileItemList.get(i); 81 | if (fileItemBean.isFinish() != FileItemBean.BLOCK_FINISH) { 82 | uploadThreadPool.execute(new UploadBlockThread(this, fileItemBean)); 83 | } 84 | } 85 | } 86 | } 87 | 88 | 89 | public boolean isCancel(){ 90 | if (multiBlockRequest==null){ 91 | return true; 92 | }else if (multiBlockRequest.isCancel()){ 93 | return true; 94 | }else { 95 | return false; 96 | } 97 | } 98 | /** 99 | * 更新 100 | * 101 | * @param fileItemBean 102 | */ 103 | public void updateFileItem(FileItemBean fileItemBean) { 104 | dbClient.getFileItemBaseDao().update(fileItemBean, DatabaseConstants.COLUMN_THREAD_NAME + "=?", new String[]{fileItemBean.getThreadName()}); 105 | } 106 | public List queryFileItemList(String bindTaskId) { 107 | return dbClient.getFileItemBaseDao().queryAction(DatabaseConstants.COLUMN_BIND_TASK_ID + "=?", new String[]{bindTaskId}); 108 | } 109 | public void insertFileTask() { 110 | dbClient.getFileTaskBaseDao().insert(multiBlockRequest.getFileTaskBean()); 111 | } 112 | public void bulkInsertFileItemList() { 113 | dbClient.getFileItemBaseDao().bulkInsert(multiBlockRequest.getFileItemList()); 114 | } 115 | public void updateFileTask(FileTaskBean fileTaskBean) { 116 | dbClient.getFileTaskBaseDao().update(fileTaskBean, DatabaseConstants.COLUMN_FILE_MD5 + "=?", new String[]{fileTaskBean.getMd5()}); 117 | } 118 | public List queryFileTaskList() { 119 | return dbClient.getFileTaskBaseDao().queryAction(DatabaseConstants.COLUMN_URL + "=?", new String[]{getUrl()}); 120 | } 121 | /** 122 | * 处理异常 123 | * 124 | * @param e 125 | */ 126 | public void handleError(final Exception e) { 127 | this.mainExecutor.execute(new Runnable() { 128 | @Override 129 | public void run() { 130 | if (isCancel()) { 131 | return; 132 | } 133 | if (multiBlockRequest.getRequestResultListener() != null) { 134 | multiBlockRequest.getRequestResultListener().error(e); 135 | } 136 | } 137 | }); 138 | } 139 | 140 | /** 141 | * 处理块的结果,判断是否上传完成 142 | * 143 | * @param content 144 | */ 145 | public void handleUpLoadFinish(final String content) { 146 | Log.i(TAG, Thread.currentThread().getName() + "handleUpLoadFinish " + " 传递给主线程 解析的内容是:"+content); 147 | if (isCancel()) { 148 | return; 149 | } 150 | int total = 0; 151 | List fileItemBeanList = multiBlockRequest.getFileItemList(); 152 | for (FileItemBean fileItemBean1 : fileItemBeanList) { 153 | if (fileItemBean1.isFinish() == FileItemBean.BLOCK_FINISH) { 154 | total++; 155 | } 156 | } 157 | //全部上传已经完成 158 | if (total == fileItemBeanList.size()) { 159 | FileTaskBean fileTaskBean = multiBlockRequest.getFileTaskBean(); 160 | fileTaskBean.setState(MultiBlockRequest.TaskConstant.task_success); 161 | fileTaskBean.setResult(content); 162 | //记录,上传文件任务已经完成了。 163 | updateFileTask(fileTaskBean); 164 | deliverResult(content); 165 | } 166 | } 167 | public void deliverProgress(final int progress) { 168 | this.mainExecutor.execute(new Runnable() { 169 | @Override 170 | public void run() { 171 | if (isCancel()){ 172 | return; 173 | } 174 | if (multiBlockRequest.getProgressListener() != null) { 175 | multiBlockRequest.getProgressListener().progress(progress); 176 | } 177 | } 178 | }); 179 | } 180 | public void deliverFileAlreadyUpLoad(final String filePath, String content){ 181 | if (isCancel()){ 182 | return; 183 | } 184 | if (multiBlockRequest.getProgressListener() != null) { 185 | final T t= multiBlockRequest.getRequestResultListener().parser(content); 186 | this.mainExecutor.execute(new Runnable() { 187 | @Override 188 | public void run() { 189 | if (isCancel()){ 190 | return; 191 | } 192 | if (multiBlockRequest.getProgressListener() != null) { 193 | multiBlockRequest.getRequestResultListener().fileAlreadyUpload(filePath,t); 194 | } 195 | } 196 | }); 197 | } 198 | } 199 | public void handleUpdate() { 200 | if (isCancel()) { 201 | return; 202 | } 203 | long total = 0; 204 | List fileItemList = multiBlockRequest.getFileItemList(); 205 | for (FileItemBean fileItemBean : fileItemList) { 206 | total += fileItemBean.getProgressIndex(); 207 | } 208 | if (isCancel()) { 209 | return; 210 | } 211 | FileTaskBean fileTaskBean = multiBlockRequest.getFileTaskBean(); 212 | int progress = (int) ((total * 100) / fileTaskBean.getFileLength()); 213 | deliverProgress(progress); 214 | } 215 | public void deliverResult(String result) { 216 | if (multiBlockRequest.getRequestResultListener() != null) { 217 | final T t = multiBlockRequest.getRequestResultListener().parser(result); 218 | this.mainExecutor.execute(new Runnable() { 219 | @Override 220 | public void run() { 221 | if (isCancel()) { 222 | return; 223 | } 224 | if (t != null) { 225 | multiBlockRequest.getRequestResultListener().success(t); 226 | multiBlockRequest.releaseResource(); 227 | } 228 | } 229 | }); 230 | } 231 | } 232 | 233 | public void destroy() { 234 | try { 235 | Thread thread = getCalculateThread(); 236 | if (thread != null) { 237 | thread.interrupt(); 238 | } 239 | if (uploadThreadPool != null) { 240 | uploadThreadPool.shutdown(); 241 | uploadThreadPool = null; 242 | } 243 | multiBlockRequest = null; 244 | } catch (Exception e) { 245 | e.printStackTrace(); 246 | } 247 | } 248 | 249 | public synchronized void setCalculateThread(Thread thread) { 250 | this.calculateThread = thread; 251 | } 252 | 253 | public synchronized Thread getCalculateThread() { 254 | return calculateThread; 255 | } 256 | 257 | public void setFileItemList(List fileItemList) { 258 | getMultiBlockRequest().setFileItemList(fileItemList); 259 | } 260 | 261 | private MultiBlockRequest getMultiBlockRequest() { 262 | return multiBlockRequest; 263 | } 264 | 265 | public int getTotalBlockSize() { 266 | return getMultiBlockRequest().getFileTaskBean().getTotalBlockSize(); 267 | } 268 | 269 | public String getFilePath() { 270 | return getMultiBlockRequest().getFilePath(); 271 | } 272 | public String getUrl() { 273 | return getMultiBlockRequest().getUrl(); 274 | } 275 | public void setMd5(String md5) { 276 | getMultiBlockRequest().setMd5(md5); 277 | } 278 | public String getMd5() { 279 | return getMultiBlockRequest().getFileTaskBean().getMd5(); 280 | } 281 | public int getThreadSize() { 282 | return threadSize; 283 | } 284 | public void setFileLength(long fileLength) { 285 | getMultiBlockRequest().setFileLength(fileLength); 286 | } 287 | 288 | public void setTotalBlockSize(int size) { 289 | getMultiBlockRequest().setTotalBlockSize(size); 290 | } 291 | public void setFileTaskBean(FileTaskBean fileTaskBean) { 292 | getMultiBlockRequest().setFileTaskBean(fileTaskBean); 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/db/DBClient.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.db; 2 | 3 | import android.content.Context; 4 | 5 | import com.xingen.okhttplib.internal.db.bean.FileItemBean; 6 | import com.xingen.okhttplib.internal.db.bean.FileTaskBean; 7 | import com.xingen.okhttplib.internal.db.dao.BaseDao; 8 | import com.xingen.okhttplib.internal.db.dao.FileItemImp; 9 | import com.xingen.okhttplib.internal.db.dao.FileTaskImp; 10 | import com.xingen.okhttplib.internal.db.sqlite.UploadFileTaskDatabase; 11 | 12 | /** 13 | * Created by ${xinGen} on 2018/1/24. 14 | * 15 | * 统一入口的数据库,管理 16 | */ 17 | 18 | public class DBClient { 19 | private static DBClient instance; 20 | private UploadFileTaskDatabase database; 21 | private BaseDao fileItemBaseDao; 22 | private BaseDao fileTaskBaseDao; 23 | static { 24 | instance = new DBClient(); 25 | } 26 | private DBClient() { 27 | this.fileItemBaseDao = FileItemImp.getInstance(); 28 | this.fileTaskBaseDao = FileTaskImp.getInstance(); 29 | } 30 | public static DBClient getInstance() { 31 | return instance; 32 | } 33 | 34 | public synchronized void init(Context context) { 35 | if (database==null){ 36 | database = new UploadFileTaskDatabase(context); 37 | this.fileItemBaseDao.setDataBase(this.database); 38 | this.fileTaskBaseDao.setDataBase(this.database); 39 | } 40 | } 41 | public BaseDao getFileItemBaseDao() { 42 | return fileItemBaseDao; 43 | } 44 | public BaseDao getFileTaskBaseDao() { 45 | return fileTaskBaseDao; 46 | } 47 | public void closeDataBase(){ 48 | if (database==null){ 49 | database.close(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/db/bean/FileItemBean.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.db.bean; 2 | 3 | import com.xingen.okhttplib.common.utils.FileUtils; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/5. 7 | *

8 | * 每个模块下载信息的实体 9 | */ 10 | 11 | public class FileItemBean { 12 | /** 13 | * 起始的角标 14 | */ 15 | private long startIndex; 16 | /** 17 | * 上传进度 18 | */ 19 | private long progressIndex; 20 | /** 21 | * 唯一标识 22 | */ 23 | private String threadName; 24 | /** 25 | * 多表关联的标识 26 | */ 27 | private String bindTaskId; 28 | /** 29 | * 当前块的角标 30 | */ 31 | private int currentBlock; 32 | /** 33 | * 快数范围值,到什么为止 34 | */ 35 | private int blockSize; 36 | /** 37 | * 是否完成 38 | */ 39 | private volatile int isFinish=0; 40 | public static final int BLOCK_FINISH=1; 41 | public int getCurrentBlock() { 42 | return currentBlock; 43 | } 44 | public void setCurrentBlock(int currentBlock) { 45 | this.currentBlock = currentBlock; 46 | } 47 | public int getBlockSize() { 48 | return blockSize; 49 | } 50 | public void setBlockSize(int blockSize) { 51 | this.blockSize = blockSize; 52 | } 53 | public String getBindTaskId() { 54 | return bindTaskId; 55 | } 56 | public String getThreadName() { 57 | return threadName; 58 | } 59 | public long getStartIndex() { 60 | return startIndex; 61 | } 62 | public void setStartIndex(long startIndex) { 63 | this.startIndex = startIndex; 64 | } 65 | public int isFinish() { 66 | return isFinish; 67 | } 68 | public void setFinish(int finish) { 69 | isFinish = finish; 70 | } 71 | /** 72 | * 计算出当前模块中上传的进度 73 | * @param total 74 | */ 75 | public void handleProgress(int total){ 76 | long chunkSize=(currentBlock-1)* FileUtils.CHUNK_LENGTH+total- startIndex; 77 | setProgressIndex(chunkSize); 78 | } 79 | private synchronized void setProgressIndex(long total){ 80 | this.progressIndex=total; 81 | } 82 | public synchronized long getProgressIndex() { 83 | return progressIndex; 84 | } 85 | public static class Builder { 86 | private FileItemBean fileItem; 87 | public Builder() { 88 | this.fileItem = new FileItemBean(); 89 | } 90 | public Builder setThreadName(String threadName) { 91 | this.fileItem.threadName = threadName; 92 | return this; 93 | } 94 | public Builder setProgressIndex(long total){ 95 | this.fileItem.progressIndex=total; 96 | return this; 97 | } 98 | public Builder setCurrentBlock(int currentBlock) { 99 | this.fileItem.currentBlock = currentBlock; 100 | return this; 101 | } 102 | public Builder setBlockSize(int totalBlockSize) { 103 | this.fileItem.blockSize = totalBlockSize; 104 | return this; 105 | } 106 | public Builder setStartIndex(long startIndex) { 107 | fileItem.startIndex = startIndex; 108 | return this; 109 | } 110 | public Builder setFinish(int finish) { 111 | this.fileItem.isFinish = finish; 112 | return this; 113 | } 114 | public Builder setBindTaskId(String bindTaskId) { 115 | this.fileItem.bindTaskId = bindTaskId; 116 | return this; 117 | } 118 | public FileItemBean builder() { 119 | return this.fileItem; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/db/bean/FileTaskBean.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.db.bean; 2 | 3 | /** 4 | * Created by ${xinGen} on 2018/1/6. 5 | */ 6 | 7 | public class FileTaskBean { 8 | /** 9 | * 下载地址 10 | */ 11 | private String url; 12 | /** 13 | * 文件存储路径 14 | */ 15 | private String filePath; 16 | /** 17 | * 下载任务文件的总长度 18 | */ 19 | private long fileLength; 20 | /** 21 | * 22 | * 文件的md5值,检验文件的唯一性 23 | * 24 | */ 25 | private String md5; 26 | /** 27 | * 是否完成 28 | */ 29 | private int state; 30 | /** 31 | * 文件分割的总块数 32 | */ 33 | private int totalBlockSize; 34 | /** 35 | * 最后的结果,包含解析的路径等等 36 | */ 37 | private String result; 38 | 39 | public String getMd5() { 40 | return md5; 41 | } 42 | 43 | public int getTotalBlockSize() { 44 | return totalBlockSize; 45 | } 46 | 47 | public void setTotalBlockSize(int totalBlockSize) { 48 | this.totalBlockSize = totalBlockSize; 49 | } 50 | 51 | public void setMd5(String md5) { 52 | this.md5 = md5; 53 | } 54 | 55 | public int getState() { 56 | return state; 57 | } 58 | public String getUrl() { 59 | return url; 60 | } 61 | public String getFilePath() { 62 | return filePath; 63 | } 64 | public long getFileLength() { 65 | return fileLength; 66 | } 67 | 68 | public void setFilePath(String filePath) { 69 | this.filePath = filePath; 70 | } 71 | public void setFileLength(long fileLength) { 72 | this.fileLength = fileLength; 73 | } 74 | public void setState(int state) { 75 | this.state = state; 76 | } 77 | 78 | public String getResult() { 79 | return result; 80 | } 81 | 82 | public void setResult(String result) { 83 | this.result = result; 84 | } 85 | 86 | public static class Builder { 87 | private FileTaskBean fileTaskBean; 88 | public Builder(){ 89 | this.fileTaskBean =new FileTaskBean(); 90 | } 91 | public Builder setState(int state) { 92 | this.fileTaskBean.state = state; 93 | return this; 94 | } 95 | public Builder setMd5(String md5) { 96 | this.fileTaskBean.md5 = md5; 97 | return this; 98 | } 99 | public Builder setDownloadUrl(String downloadUrl) { 100 | this.fileTaskBean.url = downloadUrl; 101 | return this; 102 | } 103 | public Builder setFilePath(String filePath) { 104 | this.fileTaskBean.filePath = filePath; 105 | return this; 106 | } 107 | public Builder setTotalBlockSize(int totalBlockSize) { 108 | this.fileTaskBean.totalBlockSize = totalBlockSize; 109 | return this; 110 | } 111 | public Builder setDownloadTaskLength(long downloadTaskLength) { 112 | this.fileTaskBean.fileLength = downloadTaskLength; 113 | return this; 114 | } 115 | public Builder setResult(String result) { 116 | this.fileTaskBean.result = result; 117 | return this; 118 | } 119 | public FileTaskBean builder(){ 120 | return this.fileTaskBean; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/db/dao/BaseDao.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.db.dao; 2 | 3 | import android.database.sqlite.SQLiteOpenHelper; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by ${xinGen} on 2018/1/6. 9 | */ 10 | 11 | public interface BaseDao { 12 | 13 | /** 14 | * 获取全部 15 | * @return 16 | */ 17 | List queryAll(); 18 | 19 | /** 20 | * 指定条件下的查询 21 | * @param select 22 | * @param selectArg 23 | * @return 24 | */ 25 | List queryAction(String select, String[] selectArg); 26 | 27 | /** 28 | * 新增 29 | * @param t 30 | * @return 31 | */ 32 | long insert(T t); 33 | 34 | /** 35 | * 批量插入 36 | * @param list 37 | * @return 38 | */ 39 | int bulkInsert(List list); 40 | 41 | /** 42 | * 更新 43 | * @param t 44 | * @param select 45 | * @param selectArg 46 | * @return 47 | */ 48 | int update(T t, String select, String[] selectArg); 49 | 50 | /** 51 | * 指定条件的删除 52 | * @param select 53 | * @param selectArg 54 | * @return 55 | */ 56 | int delete(String select, String[] selectArg); 57 | 58 | /** 59 | * 删除全部 60 | */ 61 | void deleteAll(); 62 | 63 | /** 64 | * 设置数据库 65 | * @param sqLiteOpenHelper 66 | */ 67 | void setDataBase(SQLiteOpenHelper sqLiteOpenHelper); 68 | } 69 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/db/dao/FileItemImp.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.db.dao; 2 | 3 | import android.content.ContentValues; 4 | import android.database.Cursor; 5 | import android.database.sqlite.SQLiteDatabase; 6 | import android.database.sqlite.SQLiteOpenHelper; 7 | 8 | 9 | import com.xingen.okhttplib.internal.db.bean.FileItemBean; 10 | import com.xingen.okhttplib.internal.db.sqlite.DatabaseConstants; 11 | import com.xingen.okhttplib.internal.db.utils.DBUtils; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * Created by ${xinGen} on 2018/1/6. 18 | */ 19 | 20 | public class FileItemImp implements BaseDao { 21 | private static FileItemImp instance; 22 | private SQLiteOpenHelper sqLiteOpenHelper; 23 | private FileItemImp() { 24 | } 25 | public static synchronized FileItemImp getInstance() { 26 | if (instance == null) { 27 | instance = new FileItemImp(); 28 | } 29 | return instance; 30 | } 31 | @Override 32 | public void setDataBase(SQLiteOpenHelper sqLiteOpenHelper) { 33 | this.sqLiteOpenHelper=sqLiteOpenHelper; 34 | } 35 | @Override 36 | public List queryAll() { 37 | return null; 38 | } 39 | private SQLiteDatabase getDataBase(){ 40 | return sqLiteOpenHelper.getWritableDatabase(); 41 | } 42 | @Override 43 | public List queryAction(String select, String[] selectArg) { 44 | List downloadItemList = new ArrayList<>(); 45 | Cursor cursor = null; 46 | 47 | try { 48 | cursor = getDataBase().query(DatabaseConstants.TABLE_NAME_FILE_ITEM, null, select, selectArg, null,null,null,null); 49 | if (cursor != null && cursor.moveToFirst()) { 50 | do { 51 | downloadItemList.add(DBUtils.createDownloadItem(cursor)); 52 | } while (cursor.moveToNext()); 53 | } 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } finally { 57 | if (cursor != null) { 58 | cursor.close(); 59 | } 60 | } 61 | return downloadItemList; 62 | } 63 | @Override 64 | public long insert(FileItemBean downloadItem) { 65 | return 0; 66 | } 67 | @Override 68 | public int bulkInsert(List list) { 69 | SQLiteDatabase sqLiteDatabase= getDataBase(); 70 | try { 71 | sqLiteDatabase.beginTransaction(); 72 | for (int i=0;i{ 20 | 21 | private static FileTaskImp instance; 22 | 23 | private FileTaskImp(){} 24 | private SQLiteOpenHelper sqLiteOpenHelper; 25 | 26 | @Override 27 | public void setDataBase(SQLiteOpenHelper sqLiteOpenHelper) { 28 | this.sqLiteOpenHelper=sqLiteOpenHelper; 29 | } 30 | public static synchronized FileTaskImp getInstance(){ 31 | if (instance==null){ 32 | instance=new FileTaskImp(); 33 | } 34 | return instance; 35 | } 36 | 37 | @Override 38 | public List queryAll() { 39 | return null; 40 | } 41 | public SQLiteDatabase getDataBase(){ 42 | return sqLiteOpenHelper.getWritableDatabase(); 43 | } 44 | @Override 45 | public List queryAction(String select, String[] selectArg) { 46 | List downloadItemList = new ArrayList<>(); 47 | Cursor cursor = null; 48 | try { 49 | cursor = getDataBase().query(DatabaseConstants.TABLE_NAME_FILE_TASK, null, select, selectArg, null,null,null); 50 | if (cursor != null && cursor.moveToFirst()) { 51 | do { 52 | downloadItemList.add(DBUtils.createDownloadTask(cursor)); 53 | } while (cursor.moveToNext()); 54 | } 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | } finally { 58 | if (cursor != null) { 59 | cursor.close(); 60 | } 61 | } 62 | return downloadItemList; 63 | } 64 | 65 | @Override 66 | public long insert(FileTaskBean downloadTaskBean) { 67 | 68 | return getDataBase().insert(DatabaseConstants.TABLE_NAME_FILE_TASK, null,DBUtils.createContentValues(downloadTaskBean)); 69 | } 70 | 71 | @Override 72 | public int bulkInsert(List list) { 73 | return 0; 74 | } 75 | 76 | @Override 77 | public int update(FileTaskBean downloadTaskBean, String select, String[] selectArg) { 78 | return this.getDataBase().update(DatabaseConstants.TABLE_NAME_FILE_TASK,DBUtils.createContentValues(downloadTaskBean),select,selectArg); 79 | } 80 | @Override 81 | public int delete(String select, String[] selectArg) { 82 | return this.getDataBase().delete(DatabaseConstants.TABLE_NAME_FILE_TASK,select,selectArg); 83 | } 84 | @Override 85 | public void deleteAll() { 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/db/sqlite/DatabaseConstants.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.db.sqlite; 2 | 3 | import android.provider.BaseColumns; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/5. 7 | */ 8 | 9 | public final class DatabaseConstants implements BaseColumns{ 10 | /** 11 | * 数据库信息 12 | */ 13 | public static final String SQLITE_NAME="fileBlockUpload.db"; 14 | public static final int SQLITE_VERSON=1; 15 | /** 16 | * 下载表,及其字段 17 | */ 18 | public static final String TABLE_NAME_FILE_TASK ="fileTask"; 19 | public static final String COLUMN_URL ="url"; 20 | public static final String COLUMN_WRITE_FILE_PATH="filePath"; 21 | public static final String COLUMN_STATE="state"; 22 | public static final String COLUMN_TASK_LENGTH="taskLength"; 23 | public static final String COLUMN_FILE_MD5="md5"; 24 | public static final String COLUMN_TOTAL_BLOCK_SIZE="totalBlockSize"; 25 | public static final String COLUMN_FILE_RESULT="fileResult"; 26 | /** 27 | * 模块下载,及其字段 28 | */ 29 | public static final String TABLE_NAME_FILE_ITEM ="fileItem"; 30 | public static final String COLUMN_BIND_TASK_ID="taskId"; 31 | public static final String COLUMN_THREAD_NAME="threadName"; 32 | public static final String COLUMN_START_INDEX="startIndex"; 33 | public static final String COLUMN_PROGRESS_INDEX ="progressIndex"; 34 | public static final String COLUMN_CURRENT_BLOCK="currentBlockIndex"; 35 | public static final String COLUMN_THREAD_BLOCK_SIZE="blockSize"; 36 | public static final String COLUMN_BLOCK_FINIS="blockFinish"; 37 | 38 | /** 39 | * 创建下载任务的表 的sql语句 40 | */ 41 | public static final String CREATE_FILE_TASK = "create table " + 42 | DatabaseConstants.TABLE_NAME_FILE_TASK + "(" + 43 | DatabaseConstants._ID + " integer primary key autoincrement," + 44 | DatabaseConstants.COLUMN_URL + " text," + 45 | DatabaseConstants.COLUMN_WRITE_FILE_PATH + " text," + 46 | DatabaseConstants.COLUMN_TASK_LENGTH + " text," + 47 | DatabaseConstants.COLUMN_FILE_MD5 + " text," + 48 | DatabaseConstants.COLUMN_FILE_RESULT + " text," + 49 | DatabaseConstants.COLUMN_TOTAL_BLOCK_SIZE + " integer," + 50 | DatabaseConstants.COLUMN_STATE + " integer" 51 | + ")"; 52 | /** 53 | * 创建多部分下载的表的sql语句 54 | */ 55 | public static final String CREATE_FILE_ITEM = "create table " + 56 | DatabaseConstants.TABLE_NAME_FILE_ITEM + "(" + 57 | DatabaseConstants._ID + " integer primary key autoincrement," + 58 | DatabaseConstants.COLUMN_START_INDEX + " integer," + 59 | DatabaseConstants.COLUMN_PROGRESS_INDEX + " integer," + 60 | DatabaseConstants.COLUMN_THREAD_NAME + " text," + 61 | DatabaseConstants.COLUMN_CURRENT_BLOCK+ " integer," + 62 | DatabaseConstants.COLUMN_BLOCK_FINIS + " integer," + 63 | DatabaseConstants.COLUMN_THREAD_BLOCK_SIZE + " integer," + 64 | DatabaseConstants.COLUMN_BIND_TASK_ID + " text" 65 | + ")"; 66 | } 67 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/db/sqlite/UploadFileTaskDatabase.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.db.sqlite; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteOpenHelper; 6 | import android.util.Log; 7 | 8 | /** 9 | * Created by ${xinGen} on 2018/1/5. 10 | */ 11 | public class UploadFileTaskDatabase extends SQLiteOpenHelper { 12 | private static final String TAG=UploadFileTaskDatabase.class.getSimpleName(); 13 | 14 | public UploadFileTaskDatabase(Context context) { 15 | super(context, DatabaseConstants.SQLITE_NAME, null, DatabaseConstants.SQLITE_VERSON); 16 | } 17 | @Override 18 | public void onCreate(SQLiteDatabase db) { 19 | Log.i(TAG, "下载任务的数据库执行 onCreate()"); 20 | db.execSQL( DatabaseConstants.CREATE_FILE_TASK); 21 | db.execSQL( DatabaseConstants.CREATE_FILE_ITEM); 22 | } 23 | @Override 24 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/db/utils/DBUtils.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.db.utils; 2 | 3 | import android.content.ContentValues; 4 | import android.database.Cursor; 5 | 6 | import com.xingen.okhttplib.internal.db.bean.FileItemBean; 7 | import com.xingen.okhttplib.internal.db.bean.FileTaskBean; 8 | import com.xingen.okhttplib.internal.db.sqlite.DatabaseConstants; 9 | 10 | 11 | /** 12 | * Created by ${xinGen} on 2018/1/16. 13 | */ 14 | 15 | public class DBUtils { 16 | public static FileItemBean createDownloadItem(Cursor cursor) { 17 | return new FileItemBean.Builder() 18 | .setStartIndex(cursor.getInt(cursor.getColumnIndex(DatabaseConstants.COLUMN_START_INDEX))) 19 | .setThreadName(cursor.getString(cursor.getColumnIndex(DatabaseConstants.COLUMN_THREAD_NAME))) 20 | .setProgressIndex(cursor.getInt(cursor.getColumnIndex(DatabaseConstants.COLUMN_PROGRESS_INDEX))) 21 | .setCurrentBlock(cursor.getInt(cursor.getColumnIndex(DatabaseConstants.COLUMN_CURRENT_BLOCK))) 22 | .setFinish(cursor.getInt(cursor.getColumnIndex(DatabaseConstants.COLUMN_BLOCK_FINIS))) 23 | .setBlockSize(cursor.getInt(cursor.getColumnIndex(DatabaseConstants.COLUMN_THREAD_BLOCK_SIZE))) 24 | .setBindTaskId(cursor.getString(cursor.getColumnIndex(DatabaseConstants.COLUMN_BIND_TASK_ID))) 25 | .builder(); 26 | } 27 | public static FileTaskBean createDownloadTask(Cursor cursor) { 28 | return new FileTaskBean.Builder() 29 | .setDownloadTaskLength(Long.valueOf(cursor.getString(cursor.getColumnIndex(DatabaseConstants.COLUMN_TASK_LENGTH)))) 30 | .setDownloadUrl(cursor.getString(cursor.getColumnIndex(DatabaseConstants.COLUMN_URL))) 31 | .setFilePath(cursor.getString(cursor.getColumnIndex(DatabaseConstants.COLUMN_WRITE_FILE_PATH))) 32 | .setResult(cursor.getString(cursor.getColumnIndex(DatabaseConstants.COLUMN_FILE_RESULT))) 33 | .setMd5(cursor.getString(cursor.getColumnIndex(DatabaseConstants.COLUMN_FILE_MD5))) 34 | .setTotalBlockSize(cursor.getInt(cursor.getColumnIndex(DatabaseConstants.COLUMN_TOTAL_BLOCK_SIZE))) 35 | .setState(cursor.getInt(cursor.getColumnIndex(DatabaseConstants.COLUMN_STATE))) 36 | .builder(); 37 | } 38 | public static ContentValues createContentValues(FileItemBean downloadItem) { 39 | ContentValues contentValues = new ContentValues(); 40 | //url需要转成特殊的字符 41 | contentValues.put(DatabaseConstants.COLUMN_BIND_TASK_ID, downloadItem.getBindTaskId()); 42 | contentValues.put(DatabaseConstants.COLUMN_START_INDEX, downloadItem.getStartIndex()); 43 | contentValues.put(DatabaseConstants.COLUMN_CURRENT_BLOCK,downloadItem.getCurrentBlock()); 44 | contentValues.put(DatabaseConstants.COLUMN_PROGRESS_INDEX,downloadItem.getProgressIndex()); 45 | contentValues.put(DatabaseConstants.COLUMN_THREAD_BLOCK_SIZE,downloadItem.getBlockSize()); 46 | contentValues.put(DatabaseConstants.COLUMN_THREAD_NAME, downloadItem.getThreadName()); 47 | contentValues.put(DatabaseConstants.COLUMN_BLOCK_FINIS, downloadItem.isFinish()); 48 | return contentValues; 49 | } 50 | public static ContentValues createContentValues(FileTaskBean downLoadTask) { 51 | ContentValues contentValues = new ContentValues(); 52 | contentValues.put(DatabaseConstants.COLUMN_URL, downLoadTask.getUrl()); 53 | contentValues.put(DatabaseConstants.COLUMN_WRITE_FILE_PATH, downLoadTask.getFilePath()); 54 | contentValues.put(DatabaseConstants.COLUMN_FILE_MD5,downLoadTask.getMd5()); 55 | contentValues.put(DatabaseConstants.COLUMN_TASK_LENGTH, String.valueOf(downLoadTask.getFileLength()) ); 56 | contentValues.put(DatabaseConstants.COLUMN_STATE,downLoadTask.getState()); 57 | contentValues.put(DatabaseConstants.COLUMN_TOTAL_BLOCK_SIZE,downLoadTask.getTotalBlockSize()); 58 | contentValues.put(DatabaseConstants.COLUMN_FILE_RESULT,downLoadTask.getResult()); 59 | return contentValues; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/dispatch/Dispatcher.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.dispatch; 2 | 3 | /** 4 | * Created by ${xinGen} on 2018/1/19. 5 | */ 6 | 7 | public interface Dispatcher { 8 | void dispatch(Runnable runnable); 9 | 10 | void destroy(); 11 | } 12 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/dispatch/ThreadDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.dispatch; 2 | 3 | import android.os.Handler; 4 | import android.os.HandlerThread; 5 | import android.os.Looper; 6 | 7 | /** 8 | * Created by ${xinGen} on 2018/1/19. 9 | * 10 | * 创建一个后台线程,执行调度任务。 11 | * 12 | */ 13 | 14 | public class ThreadDispatcher implements Dispatcher{ 15 | private static final String TAG=ThreadDispatcher.class.getName(); 16 | private HandlerThread handlerThread; 17 | private final Handler handler; 18 | private Looper looper; 19 | public ThreadDispatcher(){ 20 | this.handlerThread=new HandlerThread(TAG); 21 | this.handlerThread.start(); 22 | this.looper=this.handlerThread.getLooper(); 23 | this.handler=new Handler(this.looper); 24 | } 25 | @Override 26 | public void dispatch(Runnable runnable){ 27 | if (handler!=null){ 28 | this.handler.post(runnable); 29 | } 30 | } 31 | @Override 32 | public void destroy(){ 33 | try { 34 | this.looper.quit(); 35 | }catch (Exception e){ 36 | e.printStackTrace(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/error/CommonError.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.error; 2 | 3 | /** 4 | * Created by ${xinGen} on 2018/1/29. 5 | */ 6 | 7 | public class CommonError extends RuntimeException { 8 | private String msg; 9 | private int code; 10 | 11 | private CommonError() { 12 | } 13 | 14 | public CommonError(int state, String message) { 15 | super(message); 16 | this.msg = message; 17 | this.code = state; 18 | } 19 | 20 | public String getMsg() { 21 | return msg; 22 | } 23 | 24 | public void setMsg(String msg) { 25 | this.msg = msg; 26 | } 27 | 28 | public int getCode() { 29 | return code; 30 | } 31 | 32 | public void setCode(int code) { 33 | this.code = code; 34 | } 35 | 36 | public static class Builder { 37 | private CommonError error; 38 | 39 | public Builder() { 40 | this.error = new CommonError(); 41 | } 42 | 43 | public Builder setMsg(String msg) { 44 | this.error.msg = msg; 45 | return this; 46 | } 47 | 48 | public Builder setCode(int code) { 49 | this.error.code = code; 50 | return this; 51 | } 52 | 53 | public CommonError builder() { 54 | return error; 55 | } 56 | } 57 | 58 | public static final class State { 59 | /** 60 | * 空指针 61 | */ 62 | public static final int error_null = 1; 63 | /** 64 | * 网络异常 65 | */ 66 | public static final int error_net = 2; 67 | /** 68 | * 解析异常 69 | */ 70 | public static final int error_parser = 3; 71 | /** 72 | * 类型转换异常 73 | */ 74 | public static final int error_class = 4; 75 | /** 76 | * IO异常 77 | */ 78 | public static final int error_io=5; 79 | /** 80 | * 未知异常 81 | */ 82 | public static final int error_unknown=5; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/execute/NetExecutor.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.execute; 2 | 3 | 4 | 5 | import com.xingen.okhttplib.internal.request.BaseRequest; 6 | 7 | import okhttp3.OkHttpClient; 8 | 9 | /** 10 | * Created by ${xinGen} on 2018/1/11. 11 | * 12 | * 一个网络执行的接口 13 | */ 14 | 15 | public interface NetExecutor { 16 | void setOkHttpClient(OkHttpClient okHttpClient); 17 | void executeRequest(BaseRequest baseRequest); 18 | } 19 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/execute/NetExecutorImp.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.execute; 2 | 3 | import android.util.Log; 4 | 5 | import com.google.gson.JsonSyntaxException; 6 | import com.xingen.okhttplib.common.utils.LogUtils; 7 | import com.xingen.okhttplib.internal.error.CommonError; 8 | import com.xingen.okhttplib.internal.executor.MainExecutor; 9 | import com.xingen.okhttplib.internal.okhttp.OkHttpProvider; 10 | import com.xingen.okhttplib.internal.request.BaseRequest; 11 | import com.xingen.okhttplib.internal.response.ResponseResult; 12 | 13 | import java.io.IOException; 14 | import java.net.ConnectException; 15 | import java.net.SocketException; 16 | import java.net.SocketTimeoutException; 17 | import java.net.UnknownHostException; 18 | 19 | import okhttp3.Call; 20 | import okhttp3.OkHttpClient; 21 | import okhttp3.Request; 22 | import okhttp3.Response; 23 | 24 | /** 25 | * Created by ${xinGen} on 2018/1/19. 26 | */ 27 | 28 | public class NetExecutorImp implements NetExecutor { 29 | private final String TAG = NetExecutorImp.class.getSimpleName(); 30 | private OkHttpClient okHttpClient; 31 | private MainExecutor mainExecutor; 32 | 33 | public NetExecutorImp(MainExecutor mainExecutor) { 34 | this.mainExecutor = mainExecutor; 35 | } 36 | 37 | @Override 38 | public void setOkHttpClient(OkHttpClient okHttpClient) { 39 | this.okHttpClient = okHttpClient; 40 | } 41 | 42 | @Override 43 | public void executeRequest(final BaseRequest baseRequest) { 44 | Log.i(TAG, Thread.currentThread().getName() + " 执行网络方法 executeRequest()"); 45 | try { 46 | if (isCancel(baseRequest)) { 47 | return; 48 | } 49 | Request request = baseRequest.createOkHttpRequest(); 50 | LogUtils.i(TAG, "okhttp开始创建request "); 51 | Call call = OkHttpProvider.createCall(okHttpClient, request); 52 | baseRequest.setCall(call); 53 | if (isCancel(baseRequest)) { 54 | return; 55 | } 56 | LogUtils.i(TAG, "okhttp开始执行request "); 57 | final Response response = OkHttpProvider.executeSynchronous(call); 58 | if (isCancel(baseRequest) || response == null) { 59 | closeResource(response); 60 | return; 61 | } 62 | LogUtils.i(TAG, "okhttp 获取 response " + response); 63 | if (response.isSuccessful()) { 64 | LogUtils.i(TAG, "okhttp请求成功,开始解析 "); 65 | ResponseResult responseResult ; 66 | try { 67 | responseResult = baseRequest.parseResponse(response); 68 | }catch (JsonSyntaxException e){ 69 | responseResult=new ResponseResult(new CommonError(CommonError.State.error_parser,e.getMessage())); 70 | }catch ( IOException e){ 71 | responseResult=new ResponseResult(new CommonError(CommonError.State.error_io,e.getMessage())); 72 | }catch (NullPointerException e){ 73 | responseResult=new ResponseResult(new CommonError(CommonError.State.error_null,e.getMessage())); 74 | }catch (CommonError e){ 75 | responseResult=new ResponseResult(e); 76 | }catch (Exception e){ 77 | responseResult=new ResponseResult(new CommonError(CommonError.State.error_unknown,e.getMessage())); 78 | } 79 | this.deliverResponse(baseRequest,responseResult); 80 | } else { 81 | deliverError(new CommonError(CommonError.State.error_net,"请求失败"),baseRequest); 82 | } 83 | closeResource(response); 84 | } catch (final Exception e) { 85 | deliverError(e, baseRequest); 86 | } 87 | } 88 | 89 | private void deliverError(Exception e, final BaseRequest baseRequest) { 90 | final CommonError commonError; 91 | if (e instanceof ConnectException || e instanceof SocketTimeoutException || e instanceof UnknownHostException || e instanceof SocketException) { 92 | commonError = new CommonError(CommonError.State.error_net, e.getMessage()); 93 | } else if (e instanceof IOException) { 94 | commonError = new CommonError(CommonError.State.error_io, e.getMessage()); 95 | } else { 96 | commonError = new CommonError(CommonError.State.error_unknown, e.getMessage()); 97 | } 98 | LogUtils.i(TAG, "okhttp请求过程中发生异常 " + e.getMessage()); 99 | this.deliverResult(new Runnable() { 100 | @Override 101 | public void run() { 102 | baseRequest.deliverError(commonError); 103 | } 104 | }); 105 | } 106 | private void deliverResponse(final BaseRequest request, final ResponseResult responseResult){ 107 | this.deliverResult(new Runnable() { 108 | @Override 109 | public void run() { 110 | if (request.isCancel()){ 111 | return; 112 | } 113 | if (responseResult.error!=null){ 114 | request.deliverError(responseResult.error); 115 | }else { 116 | request.deliverResult(responseResult.t); 117 | } 118 | } 119 | }); 120 | } 121 | 122 | private void deliverResult(Runnable runnable) { 123 | this.mainExecutor.execute(runnable); 124 | } 125 | 126 | private boolean isCancel(BaseRequest baseRequest) { 127 | if (baseRequest.isCancel()) { 128 | baseRequest.releaseResource(); 129 | Log.i(TAG, TAG + " 执行过程,请求被取消"); 130 | return true; 131 | } 132 | return false; 133 | } 134 | 135 | /** 136 | * 关闭response 137 | * 138 | * @param response 139 | */ 140 | private void closeResource(Response response) { 141 | if (response != null) { 142 | response.body().close(); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/executor/MainExecutor.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.executor; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | import android.support.annotation.NonNull; 6 | 7 | import java.util.concurrent.Executor; 8 | 9 | /** 10 | * Created by ${xinGen} on 2018/1/19. 11 | * 主线程执行工具 12 | */ 13 | 14 | public class MainExecutor implements Executor { 15 | private final Handler mainHandler; 16 | public MainExecutor() { 17 | mainHandler =new Handler(Looper.getMainLooper()); 18 | } 19 | @Override 20 | public void execute(@NonNull Runnable command) { 21 | mainHandler.post(command); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/json/parser/OkHttpBaseParser.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.json.parser; 2 | 3 | import java.io.IOException; 4 | 5 | import okhttp3.Response; 6 | 7 | /** 8 | * Created by ${xinGen} on 2018/1/22. 9 | */ 10 | 11 | public interface OkHttpBaseParser { 12 | T parser(Response response) throws IOException; 13 | } 14 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/json/parser/OkHttpJsonParser.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.json.parser; 2 | 3 | import com.google.gson.Gson; 4 | import com.xingen.okhttplib.internal.json.utils.GsonUtils; 5 | 6 | import java.lang.reflect.Type; 7 | 8 | import okhttp3.Response; 9 | 10 | /** 11 | * Created by ${xinGen} on 2018/1/22. 12 | * 13 | * 参考:gson包下的 TypeToken来仿写 14 | * 15 | * 这里需要抽象类 16 | */ 17 | 18 | public abstract class OkHttpJsonParser implements OkHttpBaseParser { 19 | public Type type; 20 | private Gson gson; 21 | public OkHttpJsonParser() { 22 | this.type=GsonUtils.getSuperclassTypeParameter(getClass()); 23 | this.gson=new Gson(); 24 | } 25 | @Override 26 | public T parser(Response response) { 27 | try { 28 | String s = response.body().string(); 29 | return parser(s); 30 | }catch (Exception e){ 31 | e.printStackTrace(); 32 | } 33 | return null; 34 | } 35 | public T parser(String s){ 36 | try { 37 | 38 | 39 | T t = GsonUtils.toBean(gson, s, type); 40 | return t; 41 | }catch (Exception e){ 42 | e.printStackTrace(); 43 | } 44 | return null; 45 | } 46 | } -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/json/utils/GsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.json.utils; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.internal.$Gson$Types; 5 | import com.google.gson.reflect.TypeToken; 6 | 7 | import java.lang.reflect.ParameterizedType; 8 | import java.lang.reflect.Type; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * Created by ${xinGen} on 2018/1/10. 14 | *

15 | * Gson解析泛型类型数据的关键就是TypeToken 16 | * 17 | */ 18 | 19 | public class GsonUtils { 20 | public static T toBean(String content, Class mclass) { 21 | return toBean(new Gson(), content, mclass); 22 | } 23 | 24 | /** 25 | * 解析最基本对象 26 | * @param gson 27 | * @param content 28 | * @param mclass 29 | * @param 30 | * @return 31 | */ 32 | public static T toBean(Gson gson, String content, Class mclass) { 33 | T t = null; 34 | try { 35 | t = gson.fromJson(content, mclass); 36 | } catch (Exception e) { 37 | e.printStackTrace(); 38 | t = null; 39 | } 40 | return t; 41 | } 42 | 43 | /** 44 | * 解析实体类嵌套泛型,List嵌套泛型等等。 45 | * @param gson 46 | * @param content 47 | * @param type 48 | * @param 49 | * @return 50 | */ 51 | public static T toBean(Gson gson,String content,Type type){ 52 | try { 53 | T t=gson.fromJson(content,type); 54 | return t; 55 | }catch (Exception e){ 56 | e.printStackTrace(); 57 | } 58 | return null; 59 | } 60 | /** 61 | * 根据返回值来,制定泛型类型 62 | * 解析实体类嵌套泛型,List嵌套泛型等等。 63 | * @param gson 64 | * @param content 65 | * @param 66 | * @return 67 | */ 68 | public static T toBean(Gson gson,String content){ 69 | try { 70 | T t=gson.fromJson(content,new TypeToken(){}.getType()); 71 | return t; 72 | }catch (Exception e){ 73 | e.printStackTrace(); 74 | } 75 | return null; 76 | } 77 | 78 | /** 79 | * 80 | * @param gson 81 | * @param content 82 | * @param 83 | * @return 84 | */ 85 | public static List toBeanList(Gson gson, String content) { 86 | try { 87 | Type type = new TypeToken>() {}.getType(); 88 | List list = gson.fromJson(content, type); 89 | return list; 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | } 93 | return null; 94 | } 95 | 96 | /** 97 | * 98 | * @param gson 99 | * @param content 100 | * @param 101 | * @return 102 | */ 103 | public static Map toBeanMap(Gson gson, String content) { 104 | try { 105 | Type type = new TypeToken>() {}.getType(); 106 | Map map= gson.fromJson(content, type); 107 | return map; 108 | } catch (Exception e) { 109 | e.printStackTrace(); 110 | } 111 | return null; 112 | } 113 | public static String toJson(Object object) { 114 | return toJson(new Gson(), object); 115 | } 116 | public static String toJson(Gson gson, Object object) { 117 | String content = null; 118 | try { 119 | content = gson.toJson(object); 120 | } catch (Exception e) { 121 | e.printStackTrace(); 122 | content = null; 123 | } 124 | return content; 125 | } 126 | 127 | /** 128 | * 用于获取Class对应的Type 129 | * @param subclass 130 | * @return 131 | */ 132 | public static Type getSuperclassTypeParameter(Class subclass){ 133 | //得到带有泛型的类 134 | Type superclass = subclass.getGenericSuperclass(); 135 | if (superclass instanceof Class) { 136 | throw new RuntimeException("Missing type parameter."); 137 | } 138 | //取出当前类的泛型 139 | ParameterizedType parameter = (ParameterizedType) superclass; 140 | return $Gson$Types.canonicalize(parameter.getActualTypeArguments()[0]); 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/json/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.json.utils; 2 | 3 | import org.json.JSONObject; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/20. 7 | */ 8 | 9 | public class JsonUtils { 10 | public static String transform(JSONObject jsonObject){ 11 | return jsonObject==null?null:jsonObject.toString(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/okhttp/BlockBody.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.okhttp; 2 | 3 | import android.support.annotation.Nullable; 4 | 5 | import com.xingen.okhttplib.internal.block.FileBlockManager; 6 | import com.xingen.okhttplib.internal.db.bean.FileItemBean; 7 | 8 | 9 | import java.io.IOException; 10 | 11 | import okhttp3.MediaType; 12 | import okhttp3.RequestBody; 13 | import okio.BufferedSink; 14 | 15 | /** 16 | * Created by ${xinGen} on 2018/1/31. 17 | * 一个byte 数组的body 18 | */ 19 | 20 | public class BlockBody extends RequestBody { 21 | private byte[] bytes; 22 | //每次读取的长度,10K 23 | private static final int READ_SIZE = 10 * 1024; 24 | private FileItemBean fileItemBean; 25 | 26 | private FileBlockManager fileBlockManager; 27 | 28 | public BlockBody(byte[] bytes, FileBlockManager fileBlockManager, FileItemBean fileItemBean) { 29 | this.bytes = bytes; 30 | this.fileBlockManager=fileBlockManager; 31 | this.fileItemBean = fileItemBean; 32 | } 33 | 34 | @Nullable 35 | @Override 36 | public MediaType contentType() { 37 | return RequestBodyUtils.octet_stream_mediaType; 38 | } 39 | 40 | @Override 41 | public long contentLength() throws IOException { 42 | return bytes.length; 43 | } 44 | 45 | @Override 46 | public void writeTo(BufferedSink bufferedSink) throws IOException { 47 | try { 48 | //对传入的byte数组进行按指定大小,进行分块。 49 | int count = (bytes.length / READ_SIZE + (bytes.length % READ_SIZE != 0 ? 1 : 0)); 50 | int offset = 0; 51 | for (int i = 0; i < count; i++) { 52 | int chunk = i != count - 1 ? READ_SIZE : bytes.length - offset; 53 | //每次从byte数组写入SEGMENT_SIZE 字节,从指定位置,到结束位置 54 | bufferedSink.buffer().write(bytes, offset, chunk); 55 | bufferedSink.buffer().flush(); 56 | offset += chunk; 57 | fileItemBean.handleProgress(offset); 58 | fileBlockManager.handleUpdate(); 59 | } 60 | } catch (Exception e) { 61 | e.printStackTrace(); 62 | fileBlockManager.handleError(e); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/okhttp/FileRequestBody.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.okhttp; 2 | 3 | import android.support.annotation.Nullable; 4 | 5 | import com.xingen.okhttplib.NetClient; 6 | import com.xingen.okhttplib.common.listener.ProgressListener; 7 | import com.xingen.okhttplib.common.utils.LogUtils; 8 | import com.xingen.okhttplib.internal.executor.MainExecutor; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | 13 | import okhttp3.MediaType; 14 | import okhttp3.RequestBody; 15 | import okhttp3.internal.Util; 16 | import okio.BufferedSink; 17 | import okio.Okio; 18 | import okio.Source; 19 | 20 | /** 21 | * Created by ${xinGen} on 2018/1/24. 22 | */ 23 | 24 | public class FileRequestBody extends RequestBody { 25 | private final String tag=FileRequestBody.class.getSimpleName(); 26 | private File file; 27 | private ProgressListener progressListener; 28 | private MainExecutor mainExecutor; 29 | //每次读取的长度 30 | private static final int READ_SIZE = 10 * 1024; 31 | public FileRequestBody(File file, ProgressListener progressListener) { 32 | this(file, progressListener, NetClient.getInstance().getMainExecutor()); 33 | } 34 | public FileRequestBody(File file, ProgressListener progressListener, MainExecutor mainExecutor) { 35 | this.file = file; 36 | this.progressListener = progressListener; 37 | this.mainExecutor = mainExecutor; 38 | } 39 | @Nullable 40 | @Override 41 | public MediaType contentType() { 42 | return RequestBodyUtils.octet_stream_mediaType; 43 | } 44 | @Override 45 | public long contentLength() throws IOException { 46 | return file.length(); 47 | } 48 | @Override 49 | public void writeTo(BufferedSink bufferedSink) throws IOException { 50 | LogUtils.i(tag,tag+" 开始读写"); 51 | Source source = null; 52 | try { 53 | //文件读取流 54 | source = Okio.source(file); 55 | long total = 0; 56 | long read; 57 | while ((read = source.read(bufferedSink.buffer(), READ_SIZE)) != -1) { 58 | bufferedSink.flush(); 59 | total += read; 60 | handleProgress(total); 61 | } 62 | LogUtils.i(tag,tag+" 读写完成"); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } finally { 66 | //最后关闭流资源 67 | Util.closeQuietly(source); 68 | } 69 | } 70 | /** 71 | * 回调主线程响应 72 | * 73 | * @param total 74 | */ 75 | private void handleProgress(final long total) { 76 | this.mainExecutor.execute(new Runnable() { 77 | @Override 78 | public void run() { 79 | int progress = (int) (total * 100 / file.length()); 80 | if (progressListener != null) { 81 | progressListener.progress(progress); 82 | } 83 | } 84 | }); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/okhttp/HeaderInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.okhttp; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | import okhttp3.Interceptor; 8 | import okhttp3.Request; 9 | import okhttp3.Response; 10 | 11 | /** 12 | * Created by ${xinGen} on 2018/1/19. 13 | * 14 | * 共同的Header标头拦截器 15 | */ 16 | 17 | public class HeaderInterceptor implements Interceptor { 18 | private Map headers; 19 | public HeaderInterceptor(Map headers){ 20 | this.headers=headers; 21 | } 22 | @Override 23 | public Response intercept(Chain chain) throws IOException { 24 | Request.Builder builder= chain.request().newBuilder(); 25 | Set> set=this.headers.entrySet(); 26 | for (Map.Entry entry:set){ 27 | builder.addHeader(entry.getKey(),entry.getValue()); 28 | } 29 | return chain.proceed(builder.build()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/okhttp/HttpLoggingInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.okhttp; 2 | 3 | import java.io.EOFException; 4 | import java.io.IOException; 5 | import java.nio.charset.Charset; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import okhttp3.Connection; 9 | import okhttp3.Headers; 10 | import okhttp3.Interceptor; 11 | import okhttp3.MediaType; 12 | import okhttp3.Protocol; 13 | import okhttp3.Request; 14 | import okhttp3.RequestBody; 15 | import okhttp3.Response; 16 | import okhttp3.ResponseBody; 17 | import okhttp3.internal.http.HttpHeaders; 18 | import okhttp3.internal.platform.Platform; 19 | import okio.Buffer; 20 | import okio.BufferedSource; 21 | 22 | import static okhttp3.internal.platform.Platform.INFO; 23 | 24 | /** 25 | * Created by ${HeXinGen} on 2018/11/30. 26 | * blog博客:http://blog.csdn.net/hexingen 27 | * 28 | * 代码来源:okhttp3:logging-interceptor 29 | */ 30 | 31 | public final class HttpLoggingInterceptor implements Interceptor { 32 | private static final Charset UTF8 = Charset.forName("UTF-8"); 33 | 34 | public enum Level { 35 | /** No logs. */ 36 | NONE, 37 | 38 | HEADERS, 39 | /** 40 | * Logs request and response lines and their respective headers and bodies (if present). 41 | * 42 | *

Example: 43 | *

{@code
 44 |          * --> POST /greeting http/1.1
 45 |          * Host: example.com
 46 |          * Content-Type: plain/text
 47 |          * Content-Length: 3
 48 |          *
 49 |          * Hi?
 50 |          * --> END POST
 51 |          *
 52 |          * <-- 200 OK (22ms)
 53 |          * Content-Type: plain/text
 54 |          * Content-Length: 6
 55 |          *
 56 |          * Hello!
 57 |          * <-- END HTTP
 58 |          * }
59 | */ 60 | BODY 61 | } 62 | 63 | public interface Logger { 64 | void log(String message); 65 | 66 | /** defaults output appropriate for the current platform. */ 67 | Logger DEFAULT = new Logger() { 68 | @Override public void log(String message) { 69 | Platform.get().log(INFO, message, null); 70 | } 71 | }; 72 | } 73 | 74 | public HttpLoggingInterceptor() { 75 | this(Logger.DEFAULT); 76 | } 77 | 78 | public HttpLoggingInterceptor(Logger logger) { 79 | this.logger = logger; 80 | } 81 | 82 | private final Logger logger; 83 | 84 | private volatile Level level = HttpLoggingInterceptor.Level.NONE; 85 | 86 | /** Change the level at which this interceptor logs. */ 87 | public HttpLoggingInterceptor setLevel(HttpLoggingInterceptor.Level level) { 88 | if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead."); 89 | this.level = level; 90 | return this; 91 | } 92 | 93 | public Level getLevel() { 94 | return level; 95 | } 96 | 97 | @Override public Response intercept(Chain chain) throws IOException { 98 | Level level = this.level; 99 | 100 | Request request = chain.request(); 101 | if (level == Level.NONE) { 102 | return chain.proceed(request); 103 | } 104 | 105 | boolean logBody = level == Level.BODY; 106 | boolean logHeaders = logBody || level == Level.HEADERS; 107 | 108 | RequestBody requestBody = request.body(); 109 | boolean hasRequestBody = requestBody != null; 110 | 111 | Connection connection = chain.connection(); 112 | Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1; 113 | String requestStartMessage = "--> " + request.method() + ' ' + request.url() + ' ' + protocol; 114 | if (!logHeaders && hasRequestBody) { 115 | requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; 116 | } 117 | logger.log(requestStartMessage); 118 | 119 | if (logHeaders) { 120 | if (hasRequestBody) { 121 | // Request body headers are only present when installed as a network interceptor. Force 122 | // them to be included (when available) so there values are known. 123 | if (requestBody.contentType() != null) { 124 | logger.log("Content-Type: " + requestBody.contentType()); 125 | } 126 | if (requestBody.contentLength() != -1) { 127 | logger.log("Content-Length: " + requestBody.contentLength()); 128 | } 129 | } 130 | 131 | Headers headers = request.headers(); 132 | for (int i = 0, count = headers.size(); i < count; i++) { 133 | String name = headers.name(i); 134 | // Skip headers from the request body as they are explicitly logged above. 135 | if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) { 136 | logger.log(name + ": " + headers.value(i)); 137 | } 138 | } 139 | 140 | if (!logBody || !hasRequestBody) { 141 | logger.log("--> END " + request.method()); 142 | } else if (bodyEncoded(request.headers())) { 143 | logger.log("--> END " + request.method() + " (encoded body omitted)"); 144 | } else { 145 | Buffer buffer = new Buffer(); 146 | requestBody.writeTo(buffer); 147 | 148 | Charset charset = UTF8; 149 | MediaType contentType = requestBody.contentType(); 150 | if (contentType != null) { 151 | charset = contentType.charset(UTF8); 152 | } 153 | 154 | logger.log(""); 155 | if (isPlaintext(buffer)) { 156 | logger.log(buffer.readString(charset)); 157 | logger.log("--> END " + request.method() 158 | + " (" + requestBody.contentLength() + "-byte body)"); 159 | } else { 160 | logger.log("--> END " + request.method() + " (binary " 161 | + requestBody.contentLength() + "-byte body omitted)"); 162 | } 163 | } 164 | } 165 | 166 | long startNs = System.nanoTime(); 167 | Response response; 168 | try { 169 | response = chain.proceed(request); 170 | } catch (Exception e) { 171 | logger.log("<-- HTTP FAILED: " + e); 172 | throw e; 173 | } 174 | long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); 175 | 176 | ResponseBody responseBody = response.body(); 177 | long contentLength = responseBody.contentLength(); 178 | String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length"; 179 | logger.log("<-- " + response.code() + ' ' + response.message() + ' ' 180 | + response.request().url() + " (" + tookMs + "ms" + (!logHeaders ? ", " 181 | + bodySize + " body" : "") + ')'); 182 | 183 | if (logHeaders) { 184 | Headers headers = response.headers(); 185 | for (int i = 0, count = headers.size(); i < count; i++) { 186 | logger.log(headers.name(i) + ": " + headers.value(i)); 187 | } 188 | 189 | if (!logBody || !HttpHeaders.hasBody(response)) { 190 | logger.log("<-- END HTTP"); 191 | } else if (bodyEncoded(response.headers())) { 192 | logger.log("<-- END HTTP (encoded body omitted)"); 193 | } else { 194 | BufferedSource source = responseBody.source(); 195 | source.request(Long.MAX_VALUE); // Buffer the entire body. 196 | Buffer buffer = source.buffer(); 197 | 198 | Charset charset = UTF8; 199 | MediaType contentType = responseBody.contentType(); 200 | if (contentType != null) { 201 | charset = contentType.charset(UTF8); 202 | } 203 | 204 | if (!isPlaintext(buffer)) { 205 | logger.log(""); 206 | logger.log("<-- END HTTP (binary " + buffer.size() + "-byte body omitted)"); 207 | return response; 208 | } 209 | 210 | if (contentLength != 0) { 211 | logger.log(""); 212 | logger.log(buffer.clone().readString(charset)); 213 | } 214 | 215 | logger.log("<-- END HTTP (" + buffer.size() + "-byte body)"); 216 | } 217 | } 218 | 219 | return response; 220 | } 221 | 222 | /** 223 | * Returns true if the body in question probably contains human readable text. Uses a small sample 224 | * of code points to detect unicode control characters commonly used in binary file signatures. 225 | */ 226 | static boolean isPlaintext(Buffer buffer) { 227 | try { 228 | Buffer prefix = new Buffer(); 229 | long byteCount = buffer.size() < 64 ? buffer.size() : 64; 230 | buffer.copyTo(prefix, 0, byteCount); 231 | for (int i = 0; i < 16; i++) { 232 | if (prefix.exhausted()) { 233 | break; 234 | } 235 | int codePoint = prefix.readUtf8CodePoint(); 236 | if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) { 237 | return false; 238 | } 239 | } 240 | return true; 241 | } catch (EOFException e) { 242 | return false; // Truncated UTF-8 sequence. 243 | } 244 | } 245 | 246 | private boolean bodyEncoded(Headers headers) { 247 | String contentEncoding = headers.get("Content-Encoding"); 248 | return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); 249 | } 250 | } 251 | 252 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/okhttp/OkHttpProvider.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.okhttp; 2 | 3 | import com.xingen.okhttplib.config.NetConfig; 4 | 5 | import java.io.IOException; 6 | import java.util.Map; 7 | import java.util.Set; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import okhttp3.Call; 11 | import okhttp3.Callback; 12 | import okhttp3.MediaType; 13 | import okhttp3.OkHttpClient; 14 | import okhttp3.Request; 15 | import okhttp3.RequestBody; 16 | import okhttp3.Response; 17 | 18 | 19 | /** 20 | * Created by ${xinGen} on 2018/1/19. 21 | */ 22 | 23 | public class OkHttpProvider { 24 | public static OkHttpClient createOkHttpClient(NetConfig netConfig){ 25 | OkHttpClient.Builder builder=new OkHttpClient.Builder(); 26 | if (netConfig!=null){ 27 | if (netConfig.isLog()){ 28 | builder.addInterceptor(createLogInterceptor()); 29 | } 30 | if (netConfig.getCommonHeaders().size()>0){ 31 | builder.addInterceptor(createHeaderInterceptor(netConfig.getCommonHeaders())); 32 | } 33 | }else{ 34 | setRequestTime(builder); 35 | } 36 | return builder.build(); 37 | } 38 | 39 | private static void setRequestTime(OkHttpClient.Builder builder){ 40 | builder.connectTimeout(60, TimeUnit.SECONDS); 41 | builder.readTimeout(60,TimeUnit.SECONDS); 42 | builder.writeTimeout(60,TimeUnit.SECONDS); 43 | } 44 | /** 45 | * 共同header的烂机器 46 | * @param headers 47 | * @return 48 | */ 49 | private static HeaderInterceptor createHeaderInterceptor(Map headers){ 50 | return new HeaderInterceptor(headers); 51 | } 52 | /** 53 | * 日志的拦截器 54 | * @return 55 | */ 56 | private static HttpLoggingInterceptor createLogInterceptor (){ 57 | HttpLoggingInterceptor loggingInterceptor =new HttpLoggingInterceptor(); 58 | //打印一次请求的全部信息 59 | loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 60 | return loggingInterceptor ; 61 | } 62 | 63 | /** 64 | * 创建form表单上传的内容格式 65 | * @return 66 | */ 67 | public static MediaType createFormType(){ 68 | MediaType CONTENT_TYPE = MediaType.parse("application/x-www-form-urlencoded"); 69 | return CONTENT_TYPE; 70 | } 71 | /** 72 | * get请求 73 | * 74 | * @param url 75 | * @return 76 | */ 77 | public static Request createGetRequest(String url) { 78 | return createGetRequest(url, null); 79 | } 80 | 81 | /** 82 | * get请求 83 | * 84 | * @param url 85 | * @param headers 86 | * @return 87 | */ 88 | public static Request createGetRequest(String url, Map headers) { 89 | return createRequest(url, null, headers); 90 | } 91 | 92 | /** 93 | * post请求 94 | * 95 | * @param url 96 | * @param requestBody 97 | * @return 98 | */ 99 | public static Request createPostRequest(String url, RequestBody requestBody) { 100 | return createRequest(url, requestBody, null); 101 | } 102 | 103 | /** 104 | * post请求 105 | * 106 | * @param url 107 | * @param requestBody 108 | * @param headers 109 | * @return 110 | */ 111 | public static Request createPostRequest(String url, RequestBody requestBody, Map headers) { 112 | return createRequest(url, requestBody, headers); 113 | } 114 | 115 | /** 116 | * OkHttp 的Request 117 | * 118 | * @param url 119 | * @param requestBody 120 | * @param headers 121 | * @return 122 | */ 123 | private static Request createRequest(String url, RequestBody requestBody, Map headers) { 124 | Request.Builder builder = new Request.Builder(); 125 | builder.url(url); 126 | if (requestBody != null) { 127 | builder.post(requestBody); 128 | } 129 | if (headers != null) { 130 | Set> set = headers.entrySet(); 131 | for (Map.Entry entry : set) { 132 | builder.header(entry.getKey(), entry.getValue()); 133 | } 134 | } 135 | return builder.build(); 136 | } 137 | 138 | /** 139 | * 创建一个call,可用于取消 请求 140 | * 141 | * @param okHttpClient 142 | * @param request 143 | * @return 144 | */ 145 | public static Call createCall(OkHttpClient okHttpClient, Request request) { 146 | Call call = okHttpClient.newCall(request); 147 | return call; 148 | } 149 | 150 | /** 151 | * 异步执行 152 | * 153 | * @param call 154 | * @param responseCallback 155 | */ 156 | public static void executeAsynchronous(Call call, Callback responseCallback) { 157 | call.enqueue(responseCallback); 158 | } 159 | 160 | /** 161 | * 同步执行 162 | * 163 | * @param call 164 | * @return 165 | */ 166 | public static Response executeSynchronous(Call call) throws IOException{ 167 | Response response = call.execute(); 168 | return response; 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/okhttp/RequestBodyUtils.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.okhttp; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.xingen.okhttplib.common.listener.ProgressListener; 6 | import com.xingen.okhttplib.common.utils.FileUtils; 7 | 8 | import java.io.File; 9 | import java.util.Map; 10 | 11 | import okhttp3.Headers; 12 | import okhttp3.MediaType; 13 | import okhttp3.MultipartBody; 14 | import okhttp3.RequestBody; 15 | 16 | /** 17 | * Created by ${xinGen} on 2018/1/20. 18 | */ 19 | 20 | public class RequestBodyUtils { 21 | 22 | private static final MediaType json_mediaType = MediaType.parse("application/json;charset=utf-8"); 23 | 24 | private static final MediaType form_mediaType = MediaType.parse("application/x-www-form-urlencoded;charset=utf-8"); 25 | 26 | public static final MediaType octet_stream_mediaType = MediaType.parse("application/octet-stream"); 27 | 28 | 29 | /** 30 | * 构建json格式的body 31 | * 32 | * @param content 33 | * @return 34 | */ 35 | public static RequestBody createJsonBody(String content) { 36 | return RequestBody.create(json_mediaType, content); 37 | } 38 | 39 | /** 40 | * 构建form上传的body 41 | * 42 | * @param content 43 | * @return 44 | */ 45 | public static RequestBody createFormBody(String content) { 46 | return RequestBody.create(form_mediaType, content.getBytes()); 47 | } 48 | 49 | /** 50 | * 构建文件上传的请求 51 | * 52 | * @return 53 | */ 54 | public static RequestBody createFileBody(String filePath, ProgressListener progressListener) { 55 | MultipartBody.Builder builder = new MultipartBody.Builder(); 56 | builder.setType(MultipartBody.FORM); 57 | FileRequestBody fileRequestBody = new FileRequestBody(new File(filePath), progressListener); 58 | builder.addPart(createHeaders(filePath), fileRequestBody); 59 | return builder.build(); 60 | } 61 | public static RequestBody createBlockBody(String filePath,Map params,BlockBody blockBody){ 62 | MultipartBody.Builder builder = new MultipartBody.Builder(); 63 | builder.setType(MultipartBody.FORM); 64 | addParams(builder,params); 65 | builder.addPart(createHeaders(filePath), blockBody); 66 | return builder.build(); 67 | } 68 | /** 69 | * 创建一个Headers, 70 | * 来源于MultipartBody.Part createFormData(String name, @Nullable String filename, RequestBody body) 71 | * 72 | * @return 73 | */ 74 | private static Headers createHeaders(String filePath) { 75 | StringBuilder disposition = new StringBuilder("form-data; name="); 76 | //文件的格式:图片。啥子 77 | String fileType = "file"; 78 | disposition.append(fileType); 79 | try { 80 | String fileName = FileUtils.getFileName(filePath); 81 | if (!TextUtils.isEmpty(fileName)) { 82 | disposition.append("; filename="); 83 | disposition.append(fileName); 84 | } 85 | } catch (Exception e) { 86 | e.printStackTrace(); 87 | } 88 | return Headers.of(new String[]{"Content-Disposition", disposition.toString()}); 89 | } 90 | private static void addParams(MultipartBody.Builder builder, Map params) { 91 | 92 | if (params != null && !params.isEmpty()) { 93 | for (String key : params.keySet()) { 94 | builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + key + "\""), 95 | RequestBody.create(null, params.get(key))); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/request/BaseRequest.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.request; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.google.gson.JsonSyntaxException; 6 | import com.xingen.okhttplib.common.listener.ResultListener; 7 | import com.xingen.okhttplib.internal.error.CommonError; 8 | import com.xingen.okhttplib.internal.json.parser.OkHttpBaseParser; 9 | import com.xingen.okhttplib.internal.okhttp.OkHttpProvider; 10 | import com.xingen.okhttplib.internal.response.ResponseResult; 11 | 12 | import java.io.IOException; 13 | import java.util.Map; 14 | 15 | import okhttp3.Call; 16 | import okhttp3.Request; 17 | import okhttp3.RequestBody; 18 | import okhttp3.Response; 19 | 20 | /** 21 | * Created by ${xinGen} on 2018/1/19. 22 | */ 23 | 24 | public abstract class BaseRequest { 25 | /** 26 | * url 27 | */ 28 | private String url; 29 | /** 30 | * OkHttp请求的控制 31 | */ 32 | private Call call; 33 | /** 34 | * 是否停止 35 | */ 36 | private boolean isCancel = false; 37 | /** 38 | * 同步锁 39 | */ 40 | private final Object lock = new Object(); 41 | private ResultListener resultListener; 42 | 43 | public BaseRequest(String url, ResultListener requestResultListener) { 44 | this.url = url; 45 | this.resultListener = requestResultListener; 46 | } 47 | 48 | public ResultListener getResultListener() { 49 | return this.resultListener; 50 | } 51 | 52 | /** 53 | * 添加Header 54 | * 55 | * @param key 56 | * @param values 57 | */ 58 | public void addHeader(String key, String values) { 59 | if (getHeaders() != null && !TextUtils.isEmpty(key) && !TextUtils.isEmpty(values)) { 60 | getHeaders().put(key, values); 61 | } 62 | } 63 | 64 | public String getUrl() { 65 | return url; 66 | } 67 | 68 | public void setCall(Call call) { 69 | this.call = call; 70 | } 71 | 72 | /** 73 | * 取消操作 74 | */ 75 | public void cancel() { 76 | synchronized (lock) { 77 | isCancel = true; 78 | } 79 | if (call != null) { 80 | call.cancel(); 81 | } 82 | releaseResource(); 83 | } 84 | 85 | /** 86 | * 任务是否被取消了。 87 | * 88 | * @return 89 | */ 90 | public boolean isCancel() { 91 | synchronized (lock) { 92 | return isCancel; 93 | } 94 | } 95 | 96 | /** 97 | * 释放资源 98 | */ 99 | public void releaseResource() { 100 | this.url = null; 101 | } 102 | 103 | /** 104 | * 传递异常结果 105 | * 106 | * @param e 107 | */ 108 | public void deliverError(Exception e) { 109 | if (isCancel){ 110 | return; 111 | } 112 | if (getResultListener() != null) { 113 | getResultListener().error(e); 114 | } 115 | } 116 | 117 | public void deliverResult(T t) { 118 | if (isCancel){ 119 | return; 120 | } 121 | if (getResultListener() != null) { 122 | getResultListener().success(t); 123 | } 124 | } 125 | 126 | /** 127 | * 创建一个Request 128 | * 129 | * @return 130 | */ 131 | public Request createOkHttpRequest() { 132 | return OkHttpProvider.createPostRequest(getUrl(), getRequestBody(), getHeaders()); 133 | } 134 | 135 | /** 136 | * 采用json 解析 137 | * 138 | * @param response 139 | * @return 140 | */ 141 | protected T handleGsonParser(Response response) { 142 | if (!(resultListener instanceof OkHttpBaseParser)) { 143 | throw new CommonError.Builder() 144 | .setCode(CommonError.State.error_class) 145 | .setMsg("OkHttpBaseParser 类型转换异常") 146 | .builder(); 147 | } 148 | try { 149 | return ((OkHttpBaseParser) this.resultListener).parser(response); 150 | } catch (IOException e) { 151 | throw new CommonError.Builder() 152 | .setCode(CommonError.State.error_io) 153 | .setMsg("ResponseResult 解析出现IO异常") 154 | .builder(); 155 | } 156 | } 157 | 158 | /** 159 | * 传递结果 160 | * 161 | * @param response 162 | */ 163 | public abstract ResponseResult parseResponse(Response response) throws IOException ,NullPointerException,JsonSyntaxException; 164 | 165 | /** 166 | * 获取请求的header 167 | * 168 | * @return 169 | */ 170 | public abstract Map getHeaders(); 171 | 172 | /** 173 | * 创建各种不同的RequestBody 174 | * 175 | * @return 176 | */ 177 | protected abstract RequestBody getRequestBody(); 178 | 179 | } 180 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/request/FormRequest.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.request; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.google.gson.JsonSyntaxException; 6 | import com.xingen.okhttplib.common.listener.ResponseListener; 7 | import com.xingen.okhttplib.internal.error.CommonError; 8 | import com.xingen.okhttplib.internal.json.parser.OkHttpJsonParser; 9 | import com.xingen.okhttplib.internal.okhttp.RequestBodyUtils; 10 | import com.xingen.okhttplib.internal.response.ResponseResult; 11 | 12 | import java.util.Map; 13 | import java.util.Set; 14 | 15 | import okhttp3.RequestBody; 16 | import okhttp3.Response; 17 | 18 | /** 19 | * Created by ${xinGen} on 2018/1/20. 20 | */ 21 | 22 | public class FormRequest extends BaseRequest { 23 | private Map body; 24 | private Map headers; 25 | private RequestBody requestBody; 26 | private OkHttpJsonParser parser; 27 | public FormRequest(String url, Map body, Map map, ResponseListener requestResultListener) { 28 | super(url,requestResultListener); 29 | this.body = body; 30 | this.parser=parser; 31 | this.headers = map; 32 | } 33 | @Override 34 | public Map getHeaders() { 35 | return this.headers; 36 | } 37 | @Override 38 | protected RequestBody getRequestBody() { 39 | return getBody(); 40 | } 41 | 42 | private RequestBody getBody() { 43 | if (requestBody == null) { 44 | String content = createPostContent(); 45 | if (!TextUtils.isEmpty(content)) { 46 | requestBody = RequestBodyUtils.createFormBody(content); 47 | } 48 | } 49 | return requestBody; 50 | } 51 | private String createPostContent() { 52 | if (body == null) { 53 | return null; 54 | } else { 55 | Set> set = body.entrySet(); 56 | StringBuffer stringBuffer = new StringBuffer(); 57 | int size = 0; 58 | for (Map.Entry entry : set) { 59 | if (size != 0) { 60 | stringBuffer.append("&"); 61 | } 62 | size++; 63 | stringBuffer.append(entry.getKey()); 64 | stringBuffer.append("="); 65 | stringBuffer.append(entry.getValue()); 66 | } 67 | return stringBuffer.toString(); 68 | } 69 | } 70 | @Override 71 | public void releaseResource() { 72 | super.releaseResource(); 73 | this.requestBody = null; 74 | this.body = null; 75 | } 76 | @Override 77 | public ResponseResult parseResponse(Response response) { 78 | try { 79 | T t= this.handleGsonParser(response); 80 | return new ResponseResult(t); 81 | }catch (CommonError error){ 82 | return new ResponseResult(error); 83 | }catch (JsonSyntaxException error){ 84 | return new ResponseResult(new CommonError(CommonError.State.error_parser ,"Json解析异常 ,"+error.getMessage())); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/request/GsonRequest.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.request; 2 | 3 | import com.xingen.okhttplib.common.listener.ResponseListener; 4 | import com.xingen.okhttplib.common.listener.ResultListener; 5 | import com.xingen.okhttplib.internal.error.CommonError; 6 | import com.xingen.okhttplib.internal.json.utils.JsonUtils; 7 | import com.xingen.okhttplib.internal.okhttp.RequestBodyUtils; 8 | import com.xingen.okhttplib.internal.response.ResponseResult; 9 | 10 | import org.json.JSONObject; 11 | 12 | import java.util.Map; 13 | 14 | import okhttp3.RequestBody; 15 | import okhttp3.Response; 16 | 17 | /** 18 | * Created by ${xinGen} on 2018/1/19. 19 | */ 20 | 21 | public class GsonRequest extends BaseRequest { 22 | private String bodyContent; 23 | /** 24 | * body内容 25 | */ 26 | private RequestBody requestBody; 27 | private Map headers; 28 | public GsonRequest(String url, JSONObject jsonObject, Map map, ResponseListener requestResultListener) { 29 | this(url, JsonUtils.transform(jsonObject), map, requestResultListener); 30 | } 31 | public GsonRequest(String url, String body, Map map, ResultListener requestResultListener) { 32 | super(url, requestResultListener); 33 | 34 | this.bodyContent = body; 35 | 36 | this.headers = map; 37 | } 38 | 39 | @Override 40 | protected RequestBody getRequestBody() { 41 | return getBody(); 42 | } 43 | 44 | @Override 45 | public Map getHeaders() { 46 | return this.headers; 47 | } 48 | 49 | private RequestBody getBody() { 50 | if (requestBody == null) { 51 | requestBody = RequestBodyUtils.createJsonBody(bodyContent); 52 | } 53 | return requestBody; 54 | } 55 | 56 | @Override 57 | public ResponseResult parseResponse(Response response) { 58 | try { 59 | T t= this.handleGsonParser(response); 60 | return new ResponseResult(t); 61 | }catch (CommonError error){ 62 | return new ResponseResult(error); 63 | } 64 | } 65 | 66 | @Override 67 | public void releaseResource() { 68 | super.releaseResource(); 69 | this.bodyContent = null; 70 | this.requestBody = null; 71 | this.headers = null; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/request/MultiBlockRequest.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.request; 2 | 3 | import com.xingen.okhttplib.common.listener.FileBlockResponseListener; 4 | import com.xingen.okhttplib.common.listener.ProgressListener; 5 | import com.xingen.okhttplib.internal.block.FileBlockManager; 6 | import com.xingen.okhttplib.internal.db.bean.FileItemBean; 7 | import com.xingen.okhttplib.internal.db.bean.FileTaskBean; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Created by ${xinGen} on 2018/1/26. 13 | *

14 | * 将一个文件进行多块切割,分开上传。 15 | */ 16 | 17 | public class MultiBlockRequest { 18 | private final String TAG = MultiBlockRequest.class.getSimpleName(); 19 | /** 20 | * 是否暂停 21 | */ 22 | private volatile boolean isCancel = false; 23 | private List fileItemList; 24 | private FileTaskBean fileTaskBean; 25 | private FileBlockResponseListener requestResultListener; 26 | private ProgressListener progressListener; 27 | private FileBlockManager fileBlockManager; 28 | public MultiBlockRequest(String url, String filePath, ProgressListener progressListener, FileBlockResponseListener requestResultListener) { 29 | this.requestResultListener = requestResultListener; 30 | this.progressListener = progressListener; 31 | this.fileTaskBean = new FileTaskBean.Builder().setDownloadUrl(url).setFilePath(filePath).builder(); 32 | this.fileBlockManager = new FileBlockManager(this); 33 | } 34 | public void setFileTaskBean(FileTaskBean fileTaskBean) { 35 | this.fileTaskBean = fileTaskBean; 36 | } 37 | public String getFilePath() { 38 | return this.fileTaskBean.getFilePath(); 39 | } 40 | public String getUrl() { 41 | return this.fileTaskBean.getUrl(); 42 | } 43 | public boolean isCancel() { 44 | return isCancel; 45 | } 46 | public void setTotalBlockSize(int size) { 47 | this.fileTaskBean.setTotalBlockSize(size); 48 | } 49 | public void setFileLength(long fileLength) { 50 | this.fileTaskBean.setFileLength(fileLength); 51 | } 52 | public void setMd5(String md5) { 53 | this.fileTaskBean.setMd5(md5); 54 | } 55 | public FileTaskBean getFileTaskBean() { 56 | return fileTaskBean; 57 | } 58 | public List getFileItemList() { 59 | return fileItemList; 60 | } 61 | /** 62 | * 取消请求 63 | */ 64 | public void cancel() { 65 | try { 66 | isCancel = true; 67 | releaseResource(); 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } 71 | } 72 | public void setFileItemList(List fileItemList) { 73 | this.fileItemList = fileItemList; 74 | } 75 | /** 76 | * 释放资源 77 | */ 78 | public synchronized void releaseResource() { 79 | this.fileBlockManager.destroy(); 80 | this.requestResultListener = null; 81 | } 82 | public ProgressListener getProgressListener() { 83 | return progressListener; 84 | } 85 | public FileBlockResponseListener getRequestResultListener() { 86 | return requestResultListener; 87 | } 88 | public FileBlockManager getFileBlockManager() { 89 | return fileBlockManager; 90 | } 91 | 92 | /** 93 | * 任务状态常量 94 | */ 95 | public static final class TaskConstant { 96 | public static final int task_error = 1; 97 | public static final int task_success = 2; 98 | public static final int task_update = 3; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/request/SingleFileRequest.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.request; 2 | 3 | import com.xingen.okhttplib.common.listener.ProgressListener; 4 | import com.xingen.okhttplib.common.listener.ResponseListener; 5 | import com.xingen.okhttplib.internal.error.CommonError; 6 | import com.xingen.okhttplib.internal.okhttp.RequestBodyUtils; 7 | import com.xingen.okhttplib.internal.response.ResponseResult; 8 | 9 | import java.util.Map; 10 | 11 | import okhttp3.RequestBody; 12 | import okhttp3.Response; 13 | 14 | /** 15 | * Created by ${xinGen} on 2018/1/22. 16 | *

17 | * 单个文件上传的请求 18 | */ 19 | 20 | public class SingleFileRequest extends BaseRequest { 21 | private ProgressListener progressListener; 22 | private String filePath; 23 | private Map headers; 24 | public SingleFileRequest(String url, String filePath, Map headers, ProgressListener progressListener, ResponseListener requestResultListener) { 25 | super(url, requestResultListener); 26 | this.progressListener = progressListener; 27 | this.headers = headers; 28 | this.filePath = filePath; 29 | } 30 | 31 | @Override 32 | public ResponseResult parseResponse(Response response) { 33 | try { 34 | T t= this.handleGsonParser(response); 35 | return new ResponseResult(t); 36 | }catch (CommonError error){ 37 | return new ResponseResult(error); 38 | } 39 | } 40 | 41 | @Override 42 | public RequestBody getRequestBody() { 43 | return RequestBodyUtils.createFileBody(filePath,progressListener); 44 | } 45 | 46 | @Override 47 | public Map getHeaders() { 48 | return headers; 49 | } 50 | 51 | @Override 52 | public void releaseResource() { 53 | super.releaseResource(); 54 | this.progressListener=null; 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/response/ResponseResult.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.response; 2 | 3 | import com.xingen.okhttplib.internal.error.CommonError; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/3/12. 7 | * 响应结果 8 | */ 9 | 10 | public class ResponseResult { 11 | public T t; 12 | public CommonError error; 13 | 14 | public ResponseResult(T t) { 15 | this.t = t; 16 | } 17 | 18 | public ResponseResult(CommonError error) { 19 | this.error = error; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/thread/BaseThread.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.thread; 2 | 3 | import android.os.Process; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/19. 7 | * 8 | * 一个线程的超类 9 | */ 10 | 11 | public abstract class BaseThread implements Runnable { 12 | @Override 13 | public void run() { 14 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 15 | runTask(); 16 | } 17 | 18 | /** 19 | * 执行任务 20 | */ 21 | abstract void runTask(); 22 | } 23 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/thread/CacheThread.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.thread; 2 | 3 | import com.xingen.okhttplib.common.utils.LogUtils; 4 | import com.xingen.okhttplib.internal.request.BaseRequest; 5 | 6 | /** 7 | * Created by ${xinGen} on 2018/1/19. 8 | */ 9 | 10 | public class CacheThread extends BaseThread { 11 | private static final String TAG=CacheThread.class.getSimpleName(); 12 | private BaseRequest baseRequest; 13 | private ThreadManger threadManger; 14 | public CacheThread(BaseRequest baseRequest, ThreadManger threadManger) { 15 | this.baseRequest = baseRequest; 16 | this.threadManger = threadManger; 17 | } 18 | @Override 19 | void runTask() { 20 | try { 21 | int netThreadSize = threadManger.getNetRequestBlockingQueue().size(); 22 | if (netThreadSize < threadManger.getNetThreadSize()) { 23 | LogUtils.i(TAG,"往队列中添加一个网络任务"); 24 | this.threadManger.getNetRequestBlockingQueue().offer(baseRequest); 25 | //唤醒沉睡的线程 26 | synchronized (threadManger) { 27 | LogUtils.i(TAG,"唤醒沉睡的网络线程"); 28 | threadManger.notifyAll(); 29 | } 30 | } else { 31 | LogUtils.i(TAG,"往队列中添加一个缓存任务"); 32 | this.threadManger.getCacheRequestBlockingQueue().offer(baseRequest); 33 | } 34 | } catch (Exception e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/thread/CalculateThread.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.thread; 2 | 3 | import android.util.Log; 4 | 5 | import com.xingen.okhttplib.common.utils.FileUtils; 6 | import com.xingen.okhttplib.common.utils.LogUtils; 7 | import com.xingen.okhttplib.common.utils.MD5Utils; 8 | import com.xingen.okhttplib.internal.block.FileBlockManager; 9 | import com.xingen.okhttplib.internal.db.bean.FileItemBean; 10 | import com.xingen.okhttplib.internal.db.bean.FileTaskBean; 11 | import com.xingen.okhttplib.internal.request.MultiBlockRequest; 12 | 13 | import java.io.File; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.UUID; 17 | 18 | /** 19 | * Created by ${xinGen} on 2018/1/23. 20 | *

21 | * 分块计算的线程 22 | */ 23 | 24 | public class CalculateThread extends BaseThread { 25 | private final String TAG = CalculateThread.class.getSimpleName(); 26 | private FileBlockManager blockManager; 27 | 28 | public CalculateThread(FileBlockManager blockManager) { 29 | this.blockManager = blockManager; 30 | } 31 | 32 | @Override 33 | public void runTask() { 34 | blockManager.setCalculateThread(Thread.currentThread()); 35 | try { 36 | List fileTaskBeanList = blockManager.queryFileTaskList(); 37 | LogUtils.i(TAG, "开始获取 文件File对应的 md5值 "); 38 | String md5 = MD5Utils.borrowFileInputStream(blockManager.getFilePath()); 39 | LogUtils.i(TAG, "完成,文件File对应的 md5值是 " + md5); 40 | if (fileTaskBeanList.size() > 0) { 41 | if (Thread.interrupted()) { 42 | return; 43 | } 44 | //对记录进行检验,路径和md5需要相同 45 | FileTaskBean alreadyFileTaskBean = null; 46 | for (FileTaskBean fileTaskBean : fileTaskBeanList) { 47 | //路径相同,且md5检验结果相同,是同一个文件 48 | if (fileTaskBean.getMd5().equalsIgnoreCase(md5)) { 49 | alreadyFileTaskBean = fileTaskBean; 50 | break; 51 | } 52 | } 53 | if (alreadyFileTaskBean != null) { 54 | queryFileBlock(alreadyFileTaskBean); 55 | } else { 56 | calculateFileBlock(md5); 57 | } 58 | } else { 59 | if (Thread.interrupted()) { 60 | return; 61 | } 62 | calculateFileBlock(md5); 63 | } 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | blockManager.handleError(e); 67 | } finally { 68 | blockManager.setCalculateThread(null); 69 | Thread.interrupted(); 70 | } 71 | } 72 | 73 | /** 74 | * 查询到的文件块 75 | */ 76 | private void queryFileBlock(FileTaskBean fileTaskBean) { 77 | if (fileTaskBean.getState() == MultiBlockRequest.TaskConstant.task_success) { 78 | blockManager.deliverProgress(100); 79 | blockManager.deliverFileAlreadyUpLoad(fileTaskBean.getFilePath(),fileTaskBean.getResult()); 80 | } else { 81 | blockManager.setFileTaskBean(fileTaskBean); 82 | List fileItemBeanList = blockManager.queryFileItemList(fileTaskBean.getMd5()); 83 | if (Thread.interrupted()) { 84 | return; 85 | } 86 | //开始上传数据 87 | blockManager.setFileItemList(fileItemBeanList); 88 | blockManager.startUpLoad(); 89 | } 90 | } 91 | 92 | /** 93 | * 对文件进行分块 94 | */ 95 | private void calculateFileBlock(String md5) { 96 | blockManager.setMd5(md5); 97 | File file = new File(blockManager.getFilePath()); 98 | //文件不为空 99 | if (file != null && file.exists()) { 100 | long fileLength = file.length(); 101 | //计算多少块。 102 | int totalBlockSize = (int) ((fileLength % FileUtils.CHUNK_LENGTH) == 0 ? (fileLength / FileUtils.CHUNK_LENGTH) : (fileLength / FileUtils.CHUNK_LENGTH + 1)); 103 | List fileItemBeanList = new ArrayList<>(); 104 | //计算额外多出的余数 105 | int extraSurplus = calculateExtraSurplus(totalBlockSize); 106 | //是指定线程的备数 107 | int average = totalBlockSize / blockManager.getThreadSize(); 108 | int lastBeforeIndex = 0; 109 | for (int i = 0; i < blockManager.getThreadSize(); ++i) { 110 | int currentBlock = lastBeforeIndex + 1; 111 | int blockSize = 0; 112 | switch (i) { 113 | case 0://多出有余数(包含一个或者两个),加一 114 | blockSize = ((i + 1) * average) + (extraSurplus > 0 ? 1 : 0); 115 | break; 116 | case 1://多出有两个余数,加一 117 | blockSize = ((i + 1) * average) + (extraSurplus > 0 ? (extraSurplus > 1 ? 2 : 1) : 0); 118 | break; 119 | case 2: 120 | blockSize = totalBlockSize; 121 | break; 122 | } 123 | Log.i(TAG, " 超大文件分块中,第 " + i + "线程执行的任务块是:" + " 开始的位置 " + currentBlock + " 结束的位置 " + blockSize); 124 | lastBeforeIndex = blockSize; 125 | long startIndex = (currentBlock - 1) * FileUtils.CHUNK_LENGTH; 126 | FileItemBean fileItemBean = new FileItemBean.Builder() 127 | .setBindTaskId(blockManager.getMd5()) 128 | .setCurrentBlock(currentBlock) 129 | .setBlockSize(blockSize) 130 | .setStartIndex(startIndex) 131 | .setThreadName(UUID.randomUUID().toString()) 132 | .builder(); 133 | fileItemBeanList.add(fileItemBean); 134 | } 135 | if (Thread.interrupted()) { 136 | return; 137 | } 138 | //保存数据库 139 | blockManager.setTotalBlockSize(totalBlockSize); 140 | blockManager.setFileLength(fileLength); 141 | blockManager.setFileItemList(fileItemBeanList); 142 | blockManager.insertFileTask(); 143 | blockManager.bulkInsertFileItemList(); 144 | //开始上传数据 145 | blockManager.startUpLoad(); 146 | Log.i(TAG, " 超大文件分块中长度:" + fileLength + " 总快数:" + totalBlockSize); 147 | } else { 148 | blockManager.handleError(new Exception("文件不存在")); 149 | } 150 | } 151 | 152 | /** 153 | * 计算出来,是指定线程的倍数,多余几 154 | * 155 | * @param totalBlockSize 156 | * @return 157 | */ 158 | private int calculateExtraSurplus(int totalBlockSize) { 159 | int average = totalBlockSize / blockManager.getThreadSize(); 160 | if (average * blockManager.getThreadSize() == totalBlockSize) { 161 | return 0; 162 | } else if ((average * blockManager.getThreadSize() - 2 == totalBlockSize) || (average * blockManager.getThreadSize() + 2 == totalBlockSize)) { 163 | return 2; 164 | } else { 165 | return 1; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/thread/NetWorkThread.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.thread; 2 | 3 | import com.xingen.okhttplib.NetClient; 4 | import com.xingen.okhttplib.common.utils.LogUtils; 5 | import com.xingen.okhttplib.internal.execute.NetExecutor; 6 | import com.xingen.okhttplib.internal.request.BaseRequest; 7 | 8 | import java.util.UUID; 9 | 10 | /** 11 | * Created by ${xinGen} on 2018/1/19. 12 | * 13 | * 网络线程 14 | */ 15 | 16 | public class NetWorkThread extends BaseThread { 17 | private String threadName; 18 | private String tag=NetWorkThread .class.getSimpleName(); 19 | private ThreadManger threadManger; 20 | public NetWorkThread(ThreadManger threadManger) { 21 | this.threadManger = threadManger; 22 | this.tag= this.threadName=(tag+UUID.randomUUID().toString()); 23 | } 24 | @Override 25 | void runTask() { 26 | Thread.currentThread().setName(threadName); 27 | while (true) { 28 | try { 29 | BaseRequest netRequest = threadManger.getNetRequestBlockingQueue().poll(); 30 | if (netRequest != null) { 31 | LogUtils.i(tag, this.tag+" 开始执行网络任务 "); 32 | NetExecutor executor=NetClient.getInstance().getNetExecutor(); 33 | executor.executeRequest(netRequest); 34 | } else { 35 | LogUtils.i(tag," 开始从缓存队列获取一个任务"); 36 | int cacheThreadSize = threadManger.getCacheRequestBlockingQueue().size(); 37 | if (cacheThreadSize > 0) {//若是缓存队列中还有任务,则执行。 38 | LogUtils.i(tag," 网络线程继续执行,执行从缓存队列中的任务"); 39 | BaseRequest cacheRequest = threadManger.getCacheRequestBlockingQueue().poll(); 40 | threadManger.getNetRequestBlockingQueue().offer(cacheRequest); 41 | } else { //当缓存队列中没有任务的时候的时候,沉睡自己 42 | synchronized (threadManger) { 43 | LogUtils.i(tag," 网络线程开始沉睡"); 44 | threadManger.wait(); 45 | } 46 | } 47 | } 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | //若是线程不是中断异常,则继续执行任务。 51 | if (!(e instanceof InterruptedException)) { 52 | LogUtils.i(tag," 补捉到异常"+e.getMessage()+" 继续执行任务"); 53 | continue; 54 | }else{ 55 | LogUtils.i(tag," 补捉到中断异常 "+" 继续执行任务"); 56 | } 57 | } 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/thread/ThreadManger.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.thread; 2 | 3 | import com.xingen.okhttplib.common.utils.LogUtils; 4 | import com.xingen.okhttplib.internal.dispatch.Dispatcher; 5 | import com.xingen.okhttplib.internal.dispatch.ThreadDispatcher; 6 | import com.xingen.okhttplib.internal.request.BaseRequest; 7 | import com.xingen.okhttplib.internal.request.MultiBlockRequest; 8 | 9 | import java.util.concurrent.BlockingQueue; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | import java.util.concurrent.LinkedBlockingQueue; 13 | import java.util.concurrent.ThreadPoolExecutor; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | /** 17 | * Created by ${xinGen} on 2018/1/19. 18 | */ 19 | 20 | public class ThreadManger { 21 | private static final String TAG = ThreadManger.class.getName(); 22 | private static ThreadManger instance; 23 | /** 24 | * 线程池的配置类 25 | */ 26 | private final int CODE_POOL_SIZE; 27 | private final int maxPoolSize; 28 | private final int KEEP_ALIVE_TIME; 29 | private final TimeUnit TIME_UNIT; 30 | /** 31 | * 断点续传的网络线程的队列 32 | */ 33 | private BlockingQueue multiPartThreadBlockingQueue; 34 | /** 35 | * 断点续传的网络线程池 36 | */ 37 | private ThreadPoolExecutor multiPartThreadPool; 38 | /** 39 | * 一个任务调度的线程 40 | */ 41 | private final Dispatcher dispatcher; 42 | /** 43 | * 待调度请求的队列 44 | */ 45 | private BlockingQueue cacheRequestBlockingQueue; 46 | /** 47 | * 网络请求的队列 48 | */ 49 | private BlockingQueue netRequestBlockingQueue; 50 | /** 51 | * 大文件请求的队列 52 | */ 53 | private BlockingQueue multiBlockRequestsQueue; 54 | /** 55 | * 普通请求网络线程池 56 | */ 57 | private ExecutorService netThreadPool; 58 | /** 59 | * 网络线程的个数 60 | */ 61 | private final int NET_THREAD_SIZE = 4; 62 | static { 63 | instance = new ThreadManger(); 64 | } 65 | private ThreadManger() { 66 | //根据cpu的支持线程数来决定 67 | this.CODE_POOL_SIZE = Runtime.getRuntime().availableProcessors(); 68 | this.maxPoolSize = this.CODE_POOL_SIZE; 69 | this.KEEP_ALIVE_TIME = 1; 70 | this.TIME_UNIT = TimeUnit.SECONDS; 71 | this.multiPartThreadBlockingQueue = new LinkedBlockingQueue<>(); 72 | this.cacheRequestBlockingQueue = new LinkedBlockingQueue<>(); 73 | this.multiBlockRequestsQueue = new LinkedBlockingQueue<>(); 74 | this.netRequestBlockingQueue = new LinkedBlockingQueue<>(); 75 | this.multiPartThreadPool = new ThreadPoolExecutor(this.CODE_POOL_SIZE, this.maxPoolSize, this.KEEP_ALIVE_TIME, this.TIME_UNIT, this.multiPartThreadBlockingQueue); 76 | this.dispatcher = new ThreadDispatcher(); 77 | this.netThreadPool = createThreadPool(NET_THREAD_SIZE); 78 | //开启若干个网络线程,这里4个 79 | for (int i = 0; i < NET_THREAD_SIZE; ++i) { 80 | this.netThreadPool.execute(new NetWorkThread(this)); 81 | } 82 | } 83 | public static ThreadManger getInstance() { 84 | return instance; 85 | } 86 | public void addRequest(BaseRequest request) { 87 | this.dispatcher.dispatch(new CacheThread(request, instance)); 88 | } 89 | 90 | public void addMultiBlockRequest(MultiBlockRequest multiBlockRequest) { 91 | this.multiBlockRequestsQueue.offer(multiBlockRequest); 92 | this.multiPartThreadPool.execute(new CalculateThread(multiBlockRequest.getFileBlockManager())); 93 | } 94 | /** 95 | * 创建制定数量的线程池 96 | * @param number 97 | * @return 98 | */ 99 | public ExecutorService createThreadPool(int number) { 100 | return Executors.newFixedThreadPool(number); 101 | } 102 | /** 103 | * 销毁全部的线程 104 | */ 105 | public void destroy() { 106 | try { 107 | LogUtils.i(TAG, "销毁全部"); 108 | this.cacheRequestBlockingQueue.clear(); 109 | this.netRequestBlockingQueue.clear(); 110 | this.multiPartThreadPool.shutdownNow(); 111 | this.netThreadPool.shutdownNow(); 112 | this.dispatcher.destroy(); 113 | } catch (Exception e) { 114 | e.printStackTrace(); 115 | } 116 | } 117 | public BlockingQueue getCacheRequestBlockingQueue() { 118 | return cacheRequestBlockingQueue; 119 | } 120 | public BlockingQueue getNetRequestBlockingQueue() { 121 | return netRequestBlockingQueue; 122 | } 123 | public int getNetThreadSize() { 124 | return NET_THREAD_SIZE; 125 | } 126 | public void removeRequest(String url) { 127 | //从缓存队列中移除 128 | for (BaseRequest baseRequest :cacheRequestBlockingQueue){ 129 | if (baseRequest.getUrl().equals(url)){ 130 | cacheRequestBlockingQueue.remove(baseRequest); 131 | baseRequest.releaseResource(); 132 | } 133 | } 134 | //从网络线程中移除 135 | for (BaseRequest baseRequest:netRequestBlockingQueue){ 136 | if (baseRequest.getUrl().equals(url)){ 137 | netRequestBlockingQueue.remove(baseRequest); 138 | baseRequest.releaseResource(); 139 | } 140 | } 141 | for (MultiBlockRequest multiBlockRequest:multiBlockRequestsQueue){ 142 | if (multiBlockRequest.getUrl().equals(url)){ 143 | multiBlockRequestsQueue.remove(multiBlockRequest); 144 | } 145 | } 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/java/com/xingen/okhttplib/internal/thread/UploadBlockThread.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplib.internal.thread; 2 | 3 | import android.util.Log; 4 | 5 | import com.xingen.okhttplib.common.utils.FileUtils; 6 | import com.xingen.okhttplib.internal.block.FileBlockManager; 7 | import com.xingen.okhttplib.internal.db.bean.FileItemBean; 8 | import com.xingen.okhttplib.internal.okhttp.BlockBody; 9 | import com.xingen.okhttplib.internal.okhttp.OkHttpProvider; 10 | import com.xingen.okhttplib.internal.okhttp.RequestBodyUtils; 11 | 12 | import java.io.File; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | import okhttp3.Call; 18 | import okhttp3.OkHttpClient; 19 | import okhttp3.Request; 20 | import okhttp3.RequestBody; 21 | import okhttp3.Response; 22 | 23 | /** 24 | * Created by ${xinGen} on 2018/1/25. 25 | */ 26 | 27 | public class UploadBlockThread extends BaseThread { 28 | private final String TAG = UploadBlockThread.class.getSimpleName(); 29 | private FileItemBean fileItemBean; 30 | private File file; 31 | private int blockSize; 32 | private FileBlockManager fileBlockManager; 33 | public UploadBlockThread(FileBlockManager fileBlockManager, FileItemBean fileItemBean) { 34 | this.fileBlockManager=fileBlockManager; 35 | this.fileItemBean = fileItemBean; 36 | this.file = new File( fileBlockManager.getFilePath()); 37 | this.blockSize = FileUtils.CHUNK_LENGTH; 38 | } 39 | @Override 40 | public void runTask() { 41 | if ( fileBlockManager.isCancel()) { 42 | return; 43 | } 44 | try { 45 | OkHttpClient okHttpClient = createOkHttp(); 46 | while (fileItemBean.getCurrentBlock() <= fileItemBean.getBlockSize()) { 47 | Request request = createRequest(fileItemBean.getCurrentBlock()); 48 | Call call = OkHttpProvider.createCall(okHttpClient, request); 49 | Response response = OkHttpProvider.executeSynchronous(call); 50 | if (response.isSuccessful()) { 51 | //上传到了末尾块 52 | if (fileItemBean.getCurrentBlock() + 1 > fileItemBean.getBlockSize()) { 53 | Log.i(TAG, " 执行块,执行结束到了 " + fileItemBean.getBlockSize()); 54 | String content = response.body().string(); 55 | response.body().close(); 56 | fileItemBean.setFinish(FileItemBean.BLOCK_FINISH); 57 | fileBlockManager.updateFileItem(fileItemBean); 58 | fileBlockManager.handleUpLoadFinish(content); 59 | break; 60 | } else { 61 | Log.i(TAG, " 执行块,执行到了 " + fileItemBean.getBlockSize()); 62 | fileItemBean.setCurrentBlock(fileItemBean.getCurrentBlock() + 1); 63 | fileBlockManager.updateFileItem(fileItemBean); 64 | response.body().close(); 65 | continue; 66 | } 67 | } else { 68 | fileBlockManager.handleError(new Exception("上传失败")); 69 | response.body().close(); 70 | break; 71 | } 72 | } 73 | } catch (Exception e) { 74 | e.printStackTrace(); 75 | fileBlockManager.handleError(e); 76 | } 77 | } 78 | private String getUrl() { 79 | return fileBlockManager.getUrl(); 80 | } 81 | private RequestBody getBody(int currentBlock) { 82 | int offset = (currentBlock - 1) * FileUtils.CHUNK_LENGTH; 83 | byte[] bytes = FileUtils.getBlock(offset, file, blockSize); 84 | BlockBody blockBody = new BlockBody(bytes, fileBlockManager, fileItemBean); 85 | return RequestBodyUtils.createBlockBody( fileBlockManager.getFilePath(), getParams(currentBlock), blockBody); 86 | } 87 | private Map getParams(int currentBlock) { 88 | Map headers = new HashMap<>(); 89 | headers.put("name", FileUtils.getFileName( fileBlockManager.getFilePath())); 90 | headers.put("chunks", String.valueOf( fileBlockManager.getTotalBlockSize())); 91 | headers.put("chunk", String.valueOf(currentBlock)); 92 | return headers; 93 | } 94 | private Request createRequest(int currentBlock) { 95 | return OkHttpProvider.createPostRequest(getUrl(), getBody(currentBlock)); 96 | } 97 | private OkHttpClient createOkHttp() { 98 | OkHttpClient.Builder builder = new OkHttpClient.Builder(); 99 | builder.connectTimeout(60, TimeUnit.SECONDS) 100 | .writeTimeout(60, TimeUnit.SECONDS) 101 | .readTimeout(60, TimeUnit.SECONDS); 102 | return builder.build(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /OkHttpLibSDK/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | OkHttpLib 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **介绍**: 2 | 3 | > OkHttpLib基于okhttp为传输层,线程池调度的异步通讯网络库。支持Form表单,Json上传文本,单文件上传,超大文件分块断点多线程上传。 4 | 5 | 6 | **各种Request**: 7 | --- 8 | 9 | 众所周知,网络传输分为文本和文件传输。因此,根据业务封装了以下请求: 10 | 11 | - **FormRequest** : 12 | 13 | 类web前端中的form表单上传文本,content-type为 `application/x-www-form-urlencoded` ,返回数据采用Gson解析,生成对应的实体bean对象。 14 | 15 | - **GsonRequest**: 16 | 17 | 采用json数据结构上传文本,content-type为`application/json`,返回数据采用Gson解析,生成对应的实体bean对象。 18 | 19 | - **SingleFileRequest** 20 | 21 | 采用多部分数据结构,上传文件,content-type为`multipart/form-data`,返回数据采用Gson解析,生成对应的实体bean对象,支持进度监听器,和上传结果的回调监听器。 22 | 23 | 适合体积小的文件上传 24 | 25 | - **MultiBlockRequest**: 26 | 27 | 类似SingleFileRequest,但采用先分块,后分片的方式,数据库记录的方式实现断点多线程并发上传,避免内存溢出,避免重复上传问题。 28 | 29 | 适合超大文件上传。 30 | 31 | **使用介绍** 32 | --- 33 | 34 | **1.在module的build.gradle中,添加依赖:** 35 | ``` 36 | compile 'com.xingen:okhttplib:1.0.0' 37 | ``` 38 | 除此之外,本项目依赖okhttp和Gson库上进行功能封装,也需依赖: 39 | ``` 40 | //OkHttp的依赖 41 | compile 'com.squareup.okhttp3:okhttp:3.8.0' 42 | //gson解析库 43 | compile 'com.google.code.gson:gson:2.2.4' 44 | ``` 45 | 46 | **2. 添加权限**:添加联网权限和读写权限 47 | ``` 48 | 49 | 50 | ``` 51 | 52 | **2. 对框架中配置初始化**: 53 | 54 | 在Module项目中Application子类中的onCreate()中执行以下代码: 55 | ``` 56 | @Override 57 | public void onCreate() { 58 | super.onCreate(); 59 | 60 | //构建NetConfig配置对象,设置需要的配置。 61 | 62 | NetClient.getInstance().initSDK(this,new NetConfig.Builder().setLog(false).builder()); 63 | 64 | //或者采用默认配置 65 | NetClient.getInstance().initSDK(this); 66 | 67 | } 68 | ``` 69 | 接下,来使用各种Request。 70 | 71 | **使用JsonRequest请求**: 72 | 73 | 这里访问douban API中公开的搜索电影的接口,采用json数据结构传递,gson解析该服务器返回的信息。 74 | 75 | ```JAVA 76 | JSONObject jsonObject = null; 77 | try { 78 | jsonObject = new JSONObject(); 79 | jsonObject.put("q", "张艺谋"); 80 | } catch (Exception e) { 81 | e.printStackTrace(); 82 | } 83 | 84 | NetClient.getInstance().executeJsonRequest("https://api.douban.com/v2/movie/search", jsonObject, 85 | new ResponseListener>() { 86 | @Override 87 | public void error(Exception e) { 88 | Log.i("JsonRequest", "异常结果" + e.getMessage()); 89 | } 90 | 91 | @Override 92 | public void success(MovieList movieMovieList) { 93 | Log.i("JsonRequest", "响应结果 " + movieMovieList.toString() + " " + movieMovieList.getSubjects().get(0).getTitle()); 94 | } 95 | }); 96 | 97 | 98 | ``` 99 | **使用FormRequest请求**: 100 | 101 | 这里访问登入接口,采用form表单传递,gson解析该服务器返回的信息。 102 | ``` 103 | for (int i = 0; i < 8; ++i) { 104 | Map body = new HashMap<>(); 105 | body.put("appId", "2"); 106 | body.put("loginName", "testAdmin"); 107 | body.put("userPass", "123456"); 108 | 109 | NetClient.getInstance().executeFormRequest("http://yanfayi.cn:8889/user/login", body, 110 | new ResponseListener>() { 111 | @Override 112 | public void error(Exception e) { 113 | Log.i("FormRequest", "异常结果" + e.getMessage()); 114 | } 115 | @Override 116 | public void success(HttpResult tokenBeanHttpResult) { 117 | Log.i("FormRequest", "响应结果 " + tokenBeanHttpResult.toString() + " token是" + tokenBeanHttpResult.data.getToken()); 118 | } 119 | }); 120 | } 121 | 122 | ``` 123 | 这里并发8个网络请求访问,测试多线程并发,调度问题。 124 | 125 | **使用SingFileRequest请求**: 126 | 127 | 上传单文件,进度监听器,结果的回调监听器 128 | 129 | ``` 130 | //手机上的文件,这里,本地模拟器上存在的文件 131 | String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + "baidu.apk"; 132 | //网络的url,这里,本地Eclipse中tomcat服务器上的地址 133 | String url = "http://192.168.1.16:8080/SSMProject/file/fileUpload"; 134 | 135 | NetClient.getInstance().executeSingleFileRequest(url, filePath, 136 | new ProgressListener() { 137 | @Override 138 | public void progress(int progress) { 139 | Log.i("SingleFileRequest", "上传进度 " + progress); 140 | } 141 | }, 142 | new ResponseListener() { 143 | @Override 144 | public void error(Exception e) { 145 | Log.i("SingleFileRequest", "上传异常 " + e.getMessage()); 146 | } 147 | 148 | @Override 149 | public void success(FileBean fileBean) { 150 | Log.i("SingleFileRequest", "上传成功 " + fileBean.toString()); 151 | } 152 | }); 153 | 154 | ``` 155 | 这里,采用本地Eclipse中tomcat服务器上运行的后台项目,配合Android端口测试。 156 | 157 | 158 | **使用MultiBlockRequest请求** 159 | 160 | 对超大文件进行切割分块,分片,数据库记录,实现断点多线程并发上传。 161 | 162 | ``` 163 | //手机上的文件,这里,本地模拟器上存在的文件 164 | String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + "baihewang.apk"; 165 | //网络的url,这里,本地Eclipse中tomcat服务器上的地址 166 | String url = "http://192.168.1.16:8080/SSMProject/fileBlock/fileUpload"; 167 | 168 | NetClient.getInstance().executeMultiBlockRequest(url, filePath, 169 | new ProgressListener() { 170 | @Override 171 | public void progress(int progress) { 172 | Log.i("MultiBlockRequest", "分块上传的进度 " + progress); 173 | } 174 | }, new FileBlockResponseListener() { 175 | @Override 176 | public void error(Exception e) { 177 | Log.i("MultiBlockRequest", "分块上传失败 " + e.getMessage()); 178 | } 179 | @Override 180 | public void success(BlockBean blockBean) { 181 | Log.i("MultiBlockRequest", "分块上传成功 " + blockBean.toString()); 182 | } 183 | @Override 184 | public void fileAlreadyUpload(String filePath, BlockBean blockBean) { 185 | Log.i("MultiBlockRequest", "文件先前已经上传 "+"路径是:"+filePath+" " + blockBean.toString()); 186 | } 187 | }); 188 | 189 | ``` 190 | 191 | **如何取消请求**: 192 | 193 | 方式一:通过url取消: 194 | 195 | ``` 196 | NetClient.getInstance().cancelRequests("http://yanfayi.cn:8889/user/login") 197 | ``` 198 | 方式二: 通过对应的Request取消: 199 | ``` 200 | //多态,BaseRequest作为SingleFileRequest ,FormRequest,JsonRequest的超类。 201 | 202 | BaseRequest request=NetClient.getInstance().executeSingleFileRequest(); 203 | BaseRequest request=NetClient.getInstance().executeFormRequest(); 204 | BaseRequest request=NetClient.getInstance().executeJsonRequest(); 205 | 206 | NetClient.getInstance().cancelRequests(request); 207 | 208 | //MultiBlockRequest 与其他三种请求不在同一线程池内,作为单独的一块。 209 | MultiBlockRequest multiBlockRequest=NetClient.getInstance().executeMultiBlockRequest(); 210 | NetClient.getInstance().cancelRequests(multiBlockRequest); 211 | 212 | ``` 213 | License 214 | ------- 215 | 216 | Copyright 2018 HeXinGen. 217 | 218 | Licensed under the Apache License, Version 2.0 (the "License"); 219 | you may not use this file except in compliance with the License. 220 | You may obtain a copy of the License at 221 | 222 | http://www.apache.org/licenses/LICENSE-2.0 223 | 224 | Unless required by applicable law or agreed to in writing, software 225 | distributed under the License is distributed on an "AS IS" BASIS, 226 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 227 | See the License for the specific language governing permissions and 228 | limitations under the License. 229 | 230 | 231 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.xingen.okhttplibtest" 7 | minSdkVersion 14 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | multiDexEnabled true 13 | 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | lintOptions { 22 | abortOnError false 23 | } 24 | } 25 | 26 | dependencies { 27 | 28 | implementation fileTree(include: ['*.jar'], dir: 'libs') 29 | implementation 'com.android.support:appcompat-v7:26.1.0' 30 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 31 | 32 | compile 'com.xingen:okhttplib:1.0.0' 33 | 34 | //OkHttp的依赖 35 | compile 'com.squareup.okhttp3:okhttp:3.8.0' 36 | //gson解析库 37 | compile 'com.google.code.gson:gson:2.2.4' 38 | 39 | //compile project(':OkHttpLibSDK') 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/xingen/okhttplibtest/BaseApplication.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplibtest; 2 | 3 | import android.app.Application; 4 | 5 | import com.xingen.okhttplib.NetClient; 6 | import com.xingen.okhttplib.config.NetConfig; 7 | 8 | /** 9 | * Created by ${xinGen} on 2018/1/20. 10 | */ 11 | 12 | public class BaseApplication extends Application { 13 | @Override 14 | public void onCreate() { 15 | super.onCreate(); 16 | NetClient.getInstance().initSDK(this,new NetConfig.Builder().setLog(false).builder()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/xingen/okhttplibtest/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplibtest; 2 | 3 | import android.os.Environment; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | import android.view.View; 8 | 9 | import com.xingen.okhttplib.NetClient; 10 | import com.xingen.okhttplib.common.listener.FileBlockResponseListener; 11 | import com.xingen.okhttplib.common.listener.ProgressListener; 12 | import com.xingen.okhttplib.common.listener.ResponseListener; 13 | import com.xingen.okhttplibtest.bean.BlockBean; 14 | import com.xingen.okhttplibtest.bean.FileBean; 15 | import com.xingen.okhttplibtest.bean.HttpResult; 16 | import com.xingen.okhttplibtest.bean.Movie; 17 | import com.xingen.okhttplibtest.bean.MovieList; 18 | import com.xingen.okhttplibtest.bean.TokenBean; 19 | 20 | import org.json.JSONObject; 21 | 22 | import java.io.File; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | 26 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_main); 31 | initView(); 32 | } 33 | public void initView() { 34 | findViewById(R.id.main_json_test).setOnClickListener(this); 35 | findViewById(R.id.main_form_test).setOnClickListener(this); 36 | findViewById(R.id.main_file_test).setOnClickListener(this); 37 | findViewById(R.id.main_file_block_test).setOnClickListener(this); 38 | } 39 | @Override 40 | protected void onDestroy() { 41 | super.onDestroy(); 42 | } 43 | @Override 44 | public void onClick(View v) { 45 | switch (v.getId()) { 46 | case R.id.main_json_test: { 47 | JSONObject jsonObject = null; 48 | try { 49 | jsonObject = new JSONObject(); 50 | jsonObject.put("q", "张艺谋"); 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } 54 | NetClient.getInstance().executeJsonRequest("https://api.douban.com/v2/movie/search", jsonObject, 55 | new ResponseListener>() { 56 | @Override 57 | public void error(Exception e) { 58 | Log.i("JsonRequest", "异常结果" + e.getMessage()); 59 | } 60 | 61 | @Override 62 | public void success(MovieList movieMovieList) { 63 | Log.i("JsonRequest", "响应结果 " + movieMovieList.toString() + " " + movieMovieList.getSubjects().get(0).getTitle()); 64 | } 65 | }); 66 | 67 | } 68 | break; 69 | case R.id.main_form_test: { 70 | for (int i = 0; i < 8; ++i) { 71 | Map body = new HashMap<>(); 72 | body.put("appId", "2"); 73 | body.put("loginName", "testAdmin"); 74 | body.put("userPass", "123456"); 75 | NetClient.getInstance().executeFormRequest("http://yanfayi.cn:8889/user/login", body, 76 | new ResponseListener>() { 77 | @Override 78 | public void error(Exception e) { 79 | Log.i("FormRequest", "异常结果" + e.getMessage()); 80 | } 81 | @Override 82 | public void success(HttpResult tokenBeanHttpResult) { 83 | Log.i("FormRequest", "响应结果 " + tokenBeanHttpResult.toString() + " token是" + tokenBeanHttpResult.data.getToken()); 84 | } 85 | }); 86 | } 87 | //取消请求 88 | 89 | // NetClient.getInstance().cancelRequests("http://yanfayi.cn:8889/user/login"); 90 | } 91 | break; 92 | case R.id.main_file_test: { 93 | //手机上的文件,这里,本地模拟器上存在的文件 94 | String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + "baidu.apk"; 95 | //网络的url,这里,本地Eclipse中tomcat服务器上的地址 96 | String url = "http://192.168.1.16:8080/SSMProject/file/fileUpload"; 97 | NetClient.getInstance().executeSingleFileRequest(url, filePath, 98 | new ProgressListener() { 99 | @Override 100 | public void progress(int progress) { 101 | Log.i("SingleFileRequest", "上传进度 " + progress); 102 | } 103 | }, 104 | new ResponseListener() { 105 | @Override 106 | public void error(Exception e) { 107 | Log.i("SingleFileRequest", "上传异常 " + e.getMessage()); 108 | } 109 | 110 | @Override 111 | public void success(FileBean fileBean) { 112 | Log.i("SingleFileRequest", "上传成功 " + fileBean.toString()); 113 | } 114 | }); 115 | } 116 | break; 117 | case R.id.main_file_block_test: { 118 | //手机上的文件,这里,本地模拟器上存在的文件 119 | String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + "baihewang.apk"; 120 | //网络的url,这里,本地Eclipse中tomcat服务器上的地址 121 | String url = "http://192.168.1.16:8080/SSMProject/fileBlock/fileUpload"; 122 | NetClient.getInstance().executeMultiBlockRequest(url, filePath, 123 | new ProgressListener() { 124 | @Override 125 | public void progress(int progress) { 126 | Log.i("MultiBlockRequest", "分块上传的进度 " + progress); 127 | } 128 | }, new FileBlockResponseListener() { 129 | @Override 130 | public void error(Exception e) { 131 | Log.i("MultiBlockRequest", "分块上传失败 " + e.getMessage()); 132 | } 133 | @Override 134 | public void success(BlockBean blockBean) { 135 | Log.i("MultiBlockRequest", "分块上传成功 " + blockBean.toString()); 136 | } 137 | @Override 138 | public void fileAlreadyUpload(String filePath, BlockBean blockBean) { 139 | Log.i("MultiBlockRequest", "文件先前已经上传 "+"路径是:"+filePath+" " + blockBean.toString()); 140 | } 141 | }); 142 | } 143 | break; 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /app/src/main/java/com/xingen/okhttplibtest/bean/BlockBean.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplibtest.bean; 2 | 3 | import com.xingen.okhttplib.internal.json.utils.GsonUtils; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/27. 7 | */ 8 | 9 | public class BlockBean { 10 | private String state; 11 | private String data; 12 | private int chunk; 13 | 14 | public String getState() { 15 | return state; 16 | } 17 | 18 | public void setState(String state) { 19 | this.state = state; 20 | } 21 | 22 | public String getPath() { 23 | return data; 24 | } 25 | 26 | public void setPath(String path) { 27 | this.data = path; 28 | } 29 | 30 | public int getChunk() { 31 | return chunk; 32 | } 33 | 34 | public void setChunk(int chunk) { 35 | this.chunk = chunk; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return GsonUtils.toJson(this); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/xingen/okhttplibtest/bean/FileBean.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplibtest.bean; 2 | 3 | import com.xingen.okhttplib.internal.json.utils.GsonUtils; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/26. 7 | */ 8 | 9 | public class FileBean { 10 | private String path; 11 | 12 | public String getPath() { 13 | return path; 14 | } 15 | 16 | public void setPath(String path) { 17 | this.path = path; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return GsonUtils.toJson(this); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/xingen/okhttplibtest/bean/HttpResult.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplibtest.bean; 2 | 3 | import com.xingen.okhttplib.internal.json.utils.GsonUtils; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/20. 7 | */ 8 | 9 | public class HttpResult { 10 | public int code; 11 | public T data; 12 | @Override 13 | public String toString() { 14 | return GsonUtils.toJson(this); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/xingen/okhttplibtest/bean/Movie.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplibtest.bean; 2 | 3 | import com.xingen.okhttplib.internal.json.utils.GsonUtils; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/20. 7 | */ 8 | 9 | public class Movie { 10 | public String year; 11 | private String title; 12 | private String id; 13 | 14 | public String getYear() { 15 | return year; 16 | } 17 | 18 | public void setYear(String year) { 19 | this.year = year; 20 | } 21 | 22 | public String getTitle() { 23 | return title; 24 | } 25 | 26 | public void setTitle(String title) { 27 | this.title = title; 28 | } 29 | 30 | public String getId() { 31 | return id; 32 | } 33 | 34 | public void setId(String id) { 35 | this.id = id; 36 | } 37 | @Override 38 | public String toString() { 39 | return GsonUtils.toJson(this); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/xingen/okhttplibtest/bean/MovieList.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplibtest.bean; 2 | 3 | 4 | 5 | import com.xingen.okhttplib.internal.json.utils.GsonUtils; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Created by ${xinGen} on 2018/1/20. 11 | */ 12 | 13 | public class MovieList { 14 | public List getSubjects() { 15 | return subjects; 16 | } 17 | 18 | private List subjects; 19 | 20 | @Override 21 | public String toString() { 22 | return GsonUtils.toJson(this); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/xingen/okhttplibtest/bean/TokenBean.java: -------------------------------------------------------------------------------- 1 | package com.xingen.okhttplibtest.bean; 2 | 3 | import com.xingen.okhttplib.internal.json.utils.GsonUtils; 4 | 5 | /** 6 | * Created by ${xinGen} on 2018/1/10. 7 | */ 8 | 9 | public class TokenBean { 10 | private String token; 11 | 12 | public String getToken() { 13 | return token; 14 | } 15 | 16 | public void setToken(String token) { 17 | this.token = token; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return GsonUtils.toJson(this); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |