├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── ricky │ │ └── oknets │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── ricky │ │ │ └── oknets │ │ │ ├── HttpApi.java │ │ │ ├── MainActivity.java │ │ │ ├── OKApp.java │ │ │ ├── callback │ │ │ ├── BitmapDialogCallback.java │ │ │ ├── DialogCallback.java │ │ │ ├── JsonCallback.java │ │ │ ├── JsonConvert.java │ │ │ ├── StringDialogCallback.java │ │ │ └── show │ │ │ │ ├── JsonCallback_Customer.java │ │ │ │ └── JsonCallback_Unknow.java │ │ │ ├── common │ │ │ ├── CommonRequest.java │ │ │ └── CommonResponse.java │ │ │ ├── exception │ │ │ └── TokenException.java │ │ │ ├── model │ │ │ ├── ApkModel.java │ │ │ ├── LzyResponse.java │ │ │ ├── NewsModel.java │ │ │ ├── NewsResponse.java │ │ │ ├── RequestBean.java │ │ │ ├── ServerModel.java │ │ │ └── SimpleResponse.java │ │ │ ├── request │ │ │ └── Request.java │ │ │ └── utils │ │ │ ├── Api.java │ │ │ └── MD5Utils.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── ricky │ └── oknets │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── oknet ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── ricky │ └── oknet │ ├── OkGo.java │ ├── adapter │ ├── CacheCall.java │ ├── Call.java │ ├── CallAdapter.java │ └── DefaultCallAdapter.java │ ├── cache │ ├── CacheDao.java │ ├── CacheEntity.java │ ├── CacheHelper.java │ ├── CacheManager.java │ ├── CacheMode.java │ └── DataBaseDao.java │ ├── callback │ ├── AbsCallback.java │ ├── AbsCallbackWrapper.java │ ├── BitmapCallback.java │ ├── FileCallback.java │ └── StringCallback.java │ ├── convert │ ├── BitmapConvert.java │ ├── Converter.java │ ├── FileConvert.java │ └── StringConvert.java │ ├── cookie │ ├── CookieJarImpl.java │ └── store │ │ ├── CookieStore.java │ │ ├── MemoryCookieStore.java │ │ ├── PersistentCookieStore.java │ │ └── SerializableHttpCookie.java │ ├── exception │ ├── OkGoException.java │ ├── ServerException.java │ └── parser │ │ ├── ExceptionParseMgr.java │ │ ├── ExceptionParser.java │ │ ├── InternalExceptionParser.java │ │ ├── NetExceptionParser.java │ │ ├── ServerExceptionParser.java │ │ └── UnknowExceptionParser.java │ ├── https │ └── HttpsUtils.java │ ├── interceptor │ └── HttpLoggingInterceptor.java │ ├── lifecycle │ ├── INet.java │ ├── INetQueue.java │ └── NetQueue.java │ ├── model │ ├── HttpHeaders.java │ ├── HttpParams.java │ └── Response.java │ ├── request │ ├── BaseBodyRequest.java │ ├── BaseRequest.java │ ├── DeleteRequest.java │ ├── GetRequest.java │ ├── HasBody.java │ ├── HeadRequest.java │ ├── OptionsRequest.java │ ├── PostRequest.java │ ├── ProgressRequestBody.java │ └── PutRequest.java │ ├── retrofit │ ├── ApiProxyHandler.java │ ├── Net.java │ ├── NetRequestData.java │ └── anno │ │ ├── BYTES.java │ │ ├── BytesParam.java │ │ ├── CACHE.java │ │ ├── CacheTime.java │ │ ├── DELETE.java │ │ ├── GET.java │ │ ├── HEAD.java │ │ ├── HEADER.java │ │ ├── JSON.java │ │ ├── JsonParam.java │ │ ├── OPTIONS.java │ │ ├── POST.java │ │ ├── PUT.java │ │ ├── Param.java │ │ ├── Path.java │ │ ├── STRING.java │ │ └── StringParam.java │ ├── rx │ ├── HttpException.java │ ├── OperatorMapResponseToBodyOrError.java │ └── RxAdapter.java │ └── utils │ ├── ApiHelper.java │ ├── Cons.java │ ├── DataConvert.java │ ├── Error.java │ ├── HeaderParser.java │ ├── HttpUtils.java │ ├── INoProguard.java │ ├── JsonPrinter.java │ ├── OkLogger.java │ └── TypeUtils.java └── 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 | .idea 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OKNet 2 | 3 | > 在维护Rx支持时发现了实现良好的[okhttp-OkGo](https://github.com/jeasonlzy/okhttp-OkGo "OkGo"),作者很优秀,本着不浪费轮子的精神,将该库一些之前的特性与okhttp-OkGo结合便产生了该库,在此感谢okhttp-OkGo的作者。 4 | 5 | 6 | - 完全兼容[okhttp-OkGo](https://github.com/jeasonlzy/okhttp-OkGo "OkGo")所有用法 7 | - Rx与Callback两种api写法统一,完善的动态代理支持 8 | - 独立完善的错误分发机制,清晰且容易定制的自定义异常,再也无须手动判断Exception对象 9 | - 支持网络请求与页面绑定,网络队列可写于页面Base类中,网络请求随着页面销毁而取消 10 | - JSON请求下支持参数拦截 11 | - 支持Url占位符替换 12 | 13 | 14 | 15 | ---------- 16 | ### Api ### 17 | 18 | @GET("method") 19 | @HEADER(key = "header_key", value = "header_val") 20 | @CACHE(CacheMode.FIRST_CACHE_THEN_REQUEST) 21 | Net get(@Param("param1") String param1, @Param("param2") int param2); 22 | 23 | @POST("method") 24 | Net post(@Param("param1") String param1); 25 | 26 | @GET("cache") 27 | @CACHE(CacheMode.REQUEST_FAILED_READ_CACHE) 28 | @CacheTime(10 * 1000) 29 | Net cache(); 30 | 31 | @JSON("uploadString") 32 | Net json(@JsonParam Request.Req req); 33 | 34 | @STRING("uploadString") 35 | Net string(@StringParam String req); 36 | 37 | @GET("download") 38 | @HEADER(key = "header_key", value = "header_val") 39 | Net fileDown(@Param("param") String param1); 40 | 41 | @POST("upload") 42 | @HEADER(key = "header_key", value = "header_val") 43 | Net fileUpload(@Param("nick") String nick, @Param("avatar1") File avatar1); 44 | 45 | @GET("http://gank.io/api/data/%E7%A6%8F%E5%88%A9/{size}/{page}") 46 | Net imageList(@Path("size") int size, @Path("page") int page); 47 | 48 | 49 | ### Usage ### 50 | > 详细请下载Demo或直接查看[MainActivity](https://github.com/vihuela/OKNet/blob/master/app/src/main/java/ricky/oknets/MainActivity.java "MainActivity") 51 | 52 | ---------- 53 | 54 | > CallBack方式 55 | 56 | Api.getApi().get("param1", 2).execute(new JsonCallback() { 57 | 58 | @Override 59 | public void success(Request.Res res, boolean fromCache) { 60 | System.out.println(); 61 | } 62 | 63 | @Override 64 | public void error(Error error, String message) { 65 | System.out.println(); 66 | } 67 | 68 | }, mQueue); 69 | 70 | > Rx方式 71 | 72 | Api.getApi().get("param1", 2).rx(new JsonConvert() { 73 | }, new JsonCallback() { 74 | @Override 75 | public void success(Request.Res res, boolean fromCache) { 76 | System.out.println(); 77 | } 78 | 79 | @Override 80 | public void error(Error error, String message) { 81 | super.error(error, message); 82 | } 83 | }, mQueue); 84 | 85 | 86 | ### Demo ### 87 | 88 | >请各个回调打上断点调试 89 | 90 | 91 | ![](http://i.imgur.com/1GnKtmG.png) 92 | 93 | 94 | ### Use ### 95 | 96 | 97 | 98 | com.ricky 99 | oknet 100 | 1.2.6 101 | pom 102 | 103 | 104 | Or 105 | 106 | compile 'com.ricky:oknet:1.2.6' 107 | 108 | 109 | ### Proguard ### 110 | [https://github.com/vihuela/OKNet/blob/master/app/proguard-rules.pro](https://github.com/vihuela/OKNet/blob/master/app/proguard-rules.pro "混淆") 111 | 112 | 113 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion '25.0.0' 6 | 7 | defaultConfig { 8 | applicationId "ricky.oknets" 9 | minSdkVersion 14 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | } 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:25.2.0' 26 | compile 'com.jakewharton:butterknife:8.5.1' 27 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' 28 | compile 'com.blankj:utilcode:1.3.6' 29 | compile 'com.ricky:oknet:1.2.6' 30 | // compile project(':oknet') 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android_SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # INoProguard 20 | -keep interface ricky.oknet.utils.INoProguard {*;} 21 | -keep interface * extends ricky.oknet.utils.INoProguard {*;} 22 | -keep class * implements ricky.oknet.utils.INoProguard {*;} 23 | -keepclasseswithmembernames class * implements ricky.oknet.utils.INoProguard {*;} 24 | 25 | # Rx 26 | -keep class rx.schedulers.Schedulers { 27 | public static ; 28 | } 29 | -keep class rx.schedulers.ImmediateScheduler { 30 | public ; 31 | } 32 | -keep class rx.schedulers.TestScheduler { 33 | public ; 34 | } 35 | -keep class rx.schedulers.Schedulers { 36 | public static ** test(); 37 | } 38 | -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { 39 | long producerIndex; 40 | long consumerIndex; 41 | } 42 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { 43 | long producerNode; 44 | long consumerNode; 45 | } 46 | -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { 47 | long producerIndex; 48 | long consumerIndex; 49 | } 50 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { 51 | rx.internal.util.atomic.LinkedQueueNode producerNode; 52 | } 53 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { 54 | rx.internal.util.atomic.LinkedQueueNode consumerNode; 55 | } 56 | #okhttp 57 | -dontwarn okhttp3.** 58 | -keep class okhttp3.**{*;} 59 | -keep interface okhttp3.**{*;} -------------------------------------------------------------------------------- /app/src/androidTest/java/ricky/oknets/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/HttpApi.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets; 2 | 3 | import java.io.File; 4 | 5 | import ricky.oknet.cache.CacheMode; 6 | import ricky.oknet.retrofit.Net; 7 | import ricky.oknet.retrofit.anno.CACHE; 8 | import ricky.oknet.retrofit.anno.CacheTime; 9 | import ricky.oknet.retrofit.anno.DELETE; 10 | import ricky.oknet.retrofit.anno.GET; 11 | import ricky.oknet.retrofit.anno.HEAD; 12 | import ricky.oknet.retrofit.anno.HEADER; 13 | import ricky.oknet.retrofit.anno.JSON; 14 | import ricky.oknet.retrofit.anno.JsonParam; 15 | import ricky.oknet.retrofit.anno.OPTIONS; 16 | import ricky.oknet.retrofit.anno.POST; 17 | import ricky.oknet.retrofit.anno.PUT; 18 | import ricky.oknet.retrofit.anno.Param; 19 | import ricky.oknet.retrofit.anno.Path; 20 | import ricky.oknet.retrofit.anno.STRING; 21 | import ricky.oknet.retrofit.anno.StringParam; 22 | import ricky.oknets.request.Request; 23 | 24 | public interface HttpApi { 25 | 26 | @GET("method") 27 | @HEADER(key = "header_key", value = "header_val") 28 | @CACHE(CacheMode.FIRST_CACHE_THEN_REQUEST) 29 | Net get(@Param("param1") String param1, @Param("param2") int param2); 30 | 31 | @POST("method") 32 | Net post(@Param("param1") String param1); 33 | 34 | @HEAD("method") 35 | Net head(@Param("param1") String param1); 36 | 37 | @OPTIONS("method") 38 | Net option(@Param("param1") String param1); 39 | 40 | @PUT("method") 41 | Net put(@Param("param1") String param1); 42 | 43 | @DELETE("method") 44 | Net delete(@Param("param1") String param1); 45 | 46 | @GET("cache") 47 | @CACHE(CacheMode.REQUEST_FAILED_READ_CACHE) 48 | @CacheTime(10 * 1000) 49 | Net cache(); 50 | 51 | @JSON("uploadString") 52 | Net json(@JsonParam Request.Req req); 53 | 54 | @STRING("uploadString") 55 | Net string(@StringParam String req); 56 | 57 | @GET("download") 58 | @HEADER(key = "header_key", value = "header_val") 59 | Net fileDown(@Param("param") String param1); 60 | 61 | @POST("upload") 62 | @HEADER(key = "header_key", value = "header_val") 63 | Net fileUpload(@Param("nick") String nick, @Param("avatar1") File avatar1); 64 | 65 | //error show 66 | @GET("method") 67 | Net error_net(@Param("param1") String param1, @Param("param2") int param2); 68 | 69 | @GET("method1111") 70 | Net error_server(@Param("param1") String param1, @Param("param2") int param2); 71 | 72 | @GET("method") 73 | Net error_internal(@Param("param1") String param1, @Param("param2") int param2); 74 | 75 | @GET("http://gank.io/api/data/%E7%A6%8F%E5%88%A9/{size}/{page}") 76 | Net imageList(@Path("size") int size, @Path("page") int page/*, @Param("param") String param*/); 77 | 78 | @CACHE(CacheMode.FIRST_CACHE_THEN_REQUEST) 79 | @GET("http://news-at.zhihu.com/api/4/news/latest") 80 | Net getNewForLast(); 81 | 82 | @GET("http://news-at.zhihu.com/api/4/news/before/{date}") 83 | Net getNewForDate(@Path("date") String date); 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/OKApp.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets; 2 | 3 | import android.app.Application; 4 | 5 | import com.blankj.utilcode.utils.ToastUtils; 6 | import com.blankj.utilcode.utils.Utils; 7 | 8 | import java.util.logging.Level; 9 | 10 | import ricky.oknet.OkGo; 11 | import ricky.oknet.model.HttpHeaders; 12 | import ricky.oknet.model.HttpParams; 13 | 14 | /** 15 | * @author ricky.yao on 2016/5/10. 16 | */ 17 | public class OKApp extends Application { 18 | @Override 19 | public void onCreate() { 20 | super.onCreate(); 21 | //util 22 | Utils.init(this); 23 | ToastUtils.init(true); 24 | //net 25 | OkGo.init(this); 26 | 27 | 28 | HttpHeaders headers = new HttpHeaders(); 29 | // headers.put("commonHeaderKey1", "commonHeaderValue1"); //所有的 header 都 不支持 中文 30 | // headers.put("commonHeaderKey2", "commonHeaderValue2"); 31 | HttpParams params = new HttpParams(); 32 | // params.put("commonParamsKey1", "commonParamsValue1"); //所有的 params 都 支持 中文 33 | // params.put("commonParamsKey2", "这里支持中文参数"); 34 | 35 | OkGo.getInstance() 36 | .baseUrl("http://server.jeasonlzy.com/OkHttpUtils/") 37 | .debug("OKNet", Level.INFO, true) //是否打开调试 38 | .addCommonHeaders(headers) //设置全局公共头 39 | .addCommonParams(params); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/callback/BitmapDialogCallback.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.callback; 2 | 3 | import android.app.Activity; 4 | import android.app.ProgressDialog; 5 | import android.graphics.Bitmap; 6 | import android.support.annotation.Nullable; 7 | import android.view.Window; 8 | 9 | import ricky.oknet.callback.BitmapCallback; 10 | import ricky.oknet.request.BaseRequest; 11 | 12 | 13 | /** 14 | * ================================================ 15 | * 作 者:廖子尧 16 | * 版 本:1.0 17 | * 创建日期:2016/1/14 18 | * 描 述:请求图图片的时候显示对话框 19 | * 修订历史: 20 | * ================================================ 21 | */ 22 | public abstract class BitmapDialogCallback extends BitmapCallback { 23 | 24 | private ProgressDialog dialog; 25 | 26 | public BitmapDialogCallback(Activity activity) { 27 | dialog = new ProgressDialog(activity); 28 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 29 | dialog.setCanceledOnTouchOutside(false); 30 | dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 31 | dialog.setMessage("请求网络中..."); 32 | } 33 | 34 | @Override 35 | public void onBefore(BaseRequest request) { 36 | if (dialog != null && !dialog.isShowing()) { 37 | dialog.show(); 38 | } 39 | } 40 | 41 | @Override 42 | public void onAfter(@Nullable Bitmap bitmap, @Nullable Exception e) { 43 | if (dialog != null && dialog.isShowing()) { 44 | dialog.dismiss(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/callback/DialogCallback.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.callback; 2 | 3 | import android.app.Activity; 4 | import android.app.ProgressDialog; 5 | import android.support.annotation.Nullable; 6 | import android.view.Window; 7 | 8 | import ricky.oknet.request.BaseRequest; 9 | 10 | 11 | /** 12 | * ================================================ 13 | * 作 者:廖子尧 14 | * 版 本:1.0 15 | * 创建日期:2016/1/14 16 | * 描 述:对于网络请求是否需要弹出进度对话框 17 | * 修订历史: 18 | * ================================================ 19 | */ 20 | public abstract class DialogCallback extends JsonCallback { 21 | 22 | private ProgressDialog dialog; 23 | 24 | private void initDialog(Activity activity) { 25 | dialog = new ProgressDialog(activity); 26 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 27 | dialog.setCanceledOnTouchOutside(false); 28 | dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 29 | dialog.setMessage("请求网络中..."); 30 | } 31 | 32 | public DialogCallback(Activity activity) { 33 | super(); 34 | initDialog(activity); 35 | } 36 | 37 | @Override 38 | public void onBefore(BaseRequest request) { 39 | super.onBefore(request); 40 | //网络请求前显示对话框 41 | if (dialog != null && !dialog.isShowing()) { 42 | dialog.show(); 43 | } 44 | } 45 | 46 | @Override 47 | public void onAfter(@Nullable T t, @Nullable Exception e) { 48 | super.onAfter(t, e); 49 | //网络请求结束后关闭对话框 50 | if (dialog != null && dialog.isShowing()) { 51 | dialog.dismiss(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/callback/JsonCallback.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.callback; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.text.TextUtils; 5 | 6 | import com.google.gson.stream.JsonReader; 7 | 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.Type; 10 | 11 | import okhttp3.Call; 12 | import okhttp3.Response; 13 | import ricky.oknet.callback.AbsCallback; 14 | import ricky.oknet.exception.parser.ExceptionParser; 15 | import ricky.oknet.request.BaseRequest; 16 | import ricky.oknet.utils.DataConvert; 17 | import ricky.oknet.utils.Error; 18 | import ricky.oknets.common.CommonResponse; 19 | import ricky.oknets.exception.TokenException; 20 | 21 | /** 22 | * ricky.yao 23 | * @param 24 | */ 25 | public abstract class JsonCallback extends AbsCallback { 26 | 27 | 28 | @Override 29 | public void onBefore(BaseRequest request) { 30 | super.onBefore(request); 31 | 32 | //动态加入头字段、参数 33 | // request.headers("header1", "HeaderValue1")// 34 | // .params("params1", "ParamsValue1")// 35 | // .params("token", "3215sdf13ad1f65asd4f3ads1f"); 36 | 37 | //自定义异常解析 38 | addExceptionParser(new ExceptionParser() { 39 | @Override 40 | protected boolean handler(@NonNull Throwable e, @NonNull IHandler handler) { 41 | 42 | if (TokenException.class.isAssignableFrom(e.getClass())) { 43 | handler.onHandler(Error.Invalid, getMessageFromThrowable(e)); 44 | return true; 45 | } 46 | 47 | return false; 48 | } 49 | }); 50 | } 51 | 52 | @Override 53 | @SuppressWarnings("unchecked") 54 | public T convertSuccess(Response response) throws Exception { 55 | Type type = null; 56 | try { 57 | type = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 58 | } catch (ClassCastException e) { 59 | //没有传递泛型 60 | e.printStackTrace(); 61 | } 62 | if (type == String.class) { 63 | String responseData = response.body().string(); 64 | T t = TextUtils.isEmpty(responseData) ? (T) response.toString() : (T) responseData; 65 | response.close(); 66 | return t; 67 | } else { 68 | JsonReader jsonReader = new JsonReader(response.body().charStream()); 69 | T t = DataConvert.fromJson(jsonReader, type); 70 | response.close(); 71 | //与业务有关 72 | if (CommonResponse.class.isInstance(t)) { 73 | CommonResponse t1 = (CommonResponse) t; 74 | //t1.code = 10086;//测试自定义异常 75 | switch (t1.code) { 76 | //返回正确 77 | case 0: 78 | return t; 79 | case 10086: 80 | throw new TokenException("token is bad"); 81 | default: 82 | throw new IllegalArgumentException("unKnow error"); 83 | } 84 | 85 | } else { 86 | return t; 87 | } 88 | 89 | } 90 | } 91 | 92 | @Override 93 | public void onSuccess(T t, Call call, Response response) { 94 | success(t, false); 95 | } 96 | 97 | @Override 98 | public void onCacheSuccess(T t, Call call) { 99 | super.onCacheSuccess(t, call); 100 | success(t, true); 101 | 102 | } 103 | 104 | @Override 105 | public void onParsedError(Error error, String message) { 106 | super.onParsedError(error, message); 107 | error(error, message); 108 | } 109 | 110 | /** 111 | * 通常实现以下回调即可-------------------------------------------------------------------------- 112 | */ 113 | 114 | /** 115 | * success 116 | * 117 | * @param t t 118 | * @param fromCache 是否来自缓存 119 | */ 120 | public abstract void success(T t, boolean fromCache); 121 | 122 | /** 123 | * error 124 | * 125 | * @param error 错误类型 126 | * @param message 错误详细文本 127 | */ 128 | public void error(Error error, String message) { 129 | } 130 | 131 | 132 | } -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/callback/JsonConvert.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.callback; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.google.gson.stream.JsonReader; 6 | 7 | import java.lang.reflect.ParameterizedType; 8 | import java.lang.reflect.Type; 9 | 10 | import okhttp3.Response; 11 | import ricky.oknet.convert.Converter; 12 | import ricky.oknet.utils.DataConvert; 13 | import ricky.oknets.common.CommonResponse; 14 | import ricky.oknets.exception.TokenException; 15 | 16 | /** 17 | * ================================================ 18 | * 作 者:jeasonlzy(廖子尧)Github地址:https://github.com/jeasonlzy 19 | * 版 本:1.0 20 | * 创建日期:16/9/11 21 | * 描 述: 22 | * - 23 | * - 24 | * - 25 | * -该类主要用于 OkRx 调用,直接解析泛型,返回数据对象,若不用okrx,可以删掉该类 26 | * - 27 | * - 28 | * - 29 | * 修订历史: 30 | * ================================================ 31 | */ 32 | public class JsonConvert implements Converter { 33 | 34 | 35 | @Override 36 | @SuppressWarnings("unchecked") 37 | public T convertSuccess(Response response) throws Exception { 38 | Type type = null; 39 | try { 40 | type = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 41 | } catch (ClassCastException e) { 42 | //没有传递泛型 43 | e.printStackTrace(); 44 | } 45 | if (type == String.class) { 46 | String responseData = response.body().string(); 47 | T t = TextUtils.isEmpty(responseData) ? (T) response.toString() : (T) responseData; 48 | response.close(); 49 | return t; 50 | } else { 51 | JsonReader jsonReader = new JsonReader(response.body().charStream()); 52 | T t = DataConvert.fromJson(jsonReader, type); 53 | response.close(); 54 | //与业务有关 55 | if (CommonResponse.class.isInstance(t)) { 56 | CommonResponse t1 = (CommonResponse) t; 57 | //t1.code = 10086;//测试自定义异常 58 | switch (t1.code) { 59 | //返回正确 60 | case 0: 61 | return t; 62 | case 10086: 63 | throw new TokenException("token is bad"); 64 | default: 65 | throw new IllegalArgumentException("unKnow error"); 66 | } 67 | 68 | } else { 69 | return t; 70 | } 71 | 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/callback/StringDialogCallback.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.callback; 2 | 3 | import android.app.Activity; 4 | import android.app.ProgressDialog; 5 | import android.support.annotation.Nullable; 6 | import android.view.Window; 7 | 8 | import ricky.oknet.callback.StringCallback; 9 | import ricky.oknet.request.BaseRequest; 10 | 11 | 12 | /** 13 | * ================================================ 14 | * 作 者:jeasonlzy(廖子尧) 15 | * 版 本:1.0 16 | * 创建日期:2016/4/8 17 | * 描 述:我的Github地址 https://github.com/jeasonlzy 18 | * 修订历史: 19 | * ================================================ 20 | */ 21 | public abstract class StringDialogCallback extends StringCallback { 22 | 23 | private ProgressDialog dialog; 24 | 25 | public StringDialogCallback(Activity activity) { 26 | dialog = new ProgressDialog(activity); 27 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 28 | dialog.setCanceledOnTouchOutside(false); 29 | dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 30 | dialog.setMessage("请求网络中..."); 31 | } 32 | 33 | @Override 34 | public void onBefore(BaseRequest request) { 35 | super.onBefore(request); 36 | //网络请求前显示对话框 37 | if (dialog != null && !dialog.isShowing()) { 38 | dialog.show(); 39 | } 40 | } 41 | 42 | @Override 43 | public void onAfter(@Nullable String s, @Nullable Exception e) { 44 | super.onAfter(s, e); 45 | //网络请求结束后关闭对话框 46 | if (dialog != null && dialog.isShowing()) { 47 | dialog.dismiss(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/callback/show/JsonCallback_Customer.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.callback.show; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.text.TextUtils; 5 | 6 | import com.google.gson.stream.JsonReader; 7 | 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.Type; 10 | 11 | import okhttp3.Call; 12 | import okhttp3.Response; 13 | import ricky.oknet.callback.AbsCallback; 14 | import ricky.oknet.exception.parser.ExceptionParser; 15 | import ricky.oknet.request.BaseRequest; 16 | import ricky.oknet.utils.DataConvert; 17 | import ricky.oknet.utils.Error; 18 | import ricky.oknets.common.CommonResponse; 19 | import ricky.oknets.exception.TokenException; 20 | 21 | /** 22 | * ricky.yao 23 | * @param 24 | */ 25 | public abstract class JsonCallback_Customer extends AbsCallback { 26 | 27 | 28 | @Override 29 | public void onBefore(BaseRequest request) { 30 | super.onBefore(request); 31 | 32 | //动态加入头字段、参数 33 | // request.headers("header1", "HeaderValue1")// 34 | // .params("params1", "ParamsValue1")// 35 | // .params("token", "3215sdf13ad1f65asd4f3ads1f"); 36 | 37 | //自定义异常解析 38 | addExceptionParser(new ExceptionParser() { 39 | @Override 40 | protected boolean handler(@NonNull Throwable e, @NonNull IHandler handler) { 41 | 42 | if (TokenException.class.isAssignableFrom(e.getClass())) { 43 | handler.onHandler(Error.Invalid, getMessageFromThrowable(e)); 44 | return true; 45 | } 46 | 47 | return false; 48 | } 49 | }); 50 | } 51 | 52 | @Override 53 | @SuppressWarnings("unchecked") 54 | public T convertSuccess(Response response) throws Exception { 55 | Type type = null; 56 | try { 57 | type = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 58 | } catch (ClassCastException e) { 59 | //没有传递泛型 60 | e.printStackTrace(); 61 | } 62 | if (type == String.class) { 63 | String responseData = response.body().string(); 64 | T t = TextUtils.isEmpty(responseData) ? (T) response.toString() : (T) responseData; 65 | response.close(); 66 | return t; 67 | } else { 68 | JsonReader jsonReader = new JsonReader(response.body().charStream()); 69 | T t = DataConvert.fromJson(jsonReader, type); 70 | response.close(); 71 | //与业务有关 72 | if (CommonResponse.class.isInstance(t)) { 73 | CommonResponse t1 = (CommonResponse) t; 74 | t1.code = 10086;//模拟业务异常发生 75 | switch (t1.code) { 76 | //返回正确 77 | case 0: 78 | return t; 79 | case 10086: 80 | throw new TokenException("token is bad"); 81 | default: 82 | throw new IllegalArgumentException("unKnow error"); 83 | } 84 | 85 | } else { 86 | return t; 87 | } 88 | 89 | } 90 | } 91 | 92 | @Override 93 | public void onSuccess(T t, Call call, Response response) { 94 | success(t, false); 95 | } 96 | 97 | @Override 98 | public void onCacheSuccess(T t, Call call) { 99 | super.onCacheSuccess(t, call); 100 | success(t, true); 101 | 102 | } 103 | 104 | @Override 105 | public void onParsedError(Error error, String message) { 106 | super.onParsedError(error, message); 107 | error(error, message); 108 | } 109 | 110 | /** 111 | * 通常实现以下回调即可-------------------------------------------------------------------------- 112 | */ 113 | 114 | /** 115 | * success 116 | * 117 | * @param t t 118 | * @param fromCache 是否来自缓存 119 | */ 120 | public abstract void success(T t, boolean fromCache); 121 | 122 | /** 123 | * error 124 | * 125 | * @param error 错误类型 126 | * @param message 错误详细文本 127 | */ 128 | public void error(Error error, String message) { 129 | } 130 | 131 | 132 | } -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/callback/show/JsonCallback_Unknow.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.callback.show; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.text.TextUtils; 5 | 6 | import com.google.gson.stream.JsonReader; 7 | 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.Type; 10 | 11 | import okhttp3.Call; 12 | import okhttp3.Response; 13 | import ricky.oknet.callback.AbsCallback; 14 | import ricky.oknet.exception.parser.ExceptionParser; 15 | import ricky.oknet.request.BaseRequest; 16 | import ricky.oknet.utils.DataConvert; 17 | import ricky.oknet.utils.Error; 18 | import ricky.oknets.common.CommonResponse; 19 | import ricky.oknets.exception.TokenException; 20 | 21 | /** 22 | * ricky.yao 23 | * @param 24 | */ 25 | public abstract class JsonCallback_Unknow extends AbsCallback { 26 | 27 | 28 | @Override 29 | public void onBefore(BaseRequest request) { 30 | super.onBefore(request); 31 | 32 | //动态加入头字段、参数 33 | // request.headers("header1", "HeaderValue1")// 34 | // .params("params1", "ParamsValue1")// 35 | // .params("token", "3215sdf13ad1f65asd4f3ads1f"); 36 | 37 | //自定义异常解析 38 | addExceptionParser(new ExceptionParser() { 39 | @Override 40 | protected boolean handler(@NonNull Throwable e, @NonNull IHandler handler) { 41 | 42 | if (TokenException.class.isAssignableFrom(e.getClass())) { 43 | handler.onHandler(Error.Invalid, getMessageFromThrowable(e)); 44 | return true; 45 | } 46 | 47 | return false; 48 | } 49 | }); 50 | } 51 | 52 | @Override 53 | @SuppressWarnings("unchecked") 54 | public T convertSuccess(Response response) throws Exception { 55 | Type type = null; 56 | try { 57 | type = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 58 | } catch (ClassCastException e) { 59 | //没有传递泛型 60 | e.printStackTrace(); 61 | } 62 | if (type == String.class) { 63 | String responseData = response.body().string(); 64 | T t = TextUtils.isEmpty(responseData) ? (T) response.toString() : (T) responseData; 65 | response.close(); 66 | return t; 67 | } else { 68 | JsonReader jsonReader = new JsonReader(response.body().charStream()); 69 | T t = DataConvert.fromJson(jsonReader, type); 70 | response.close(); 71 | //与业务有关 72 | if (CommonResponse.class.isInstance(t)) { 73 | CommonResponse t1 = (CommonResponse) t; 74 | t1.code = 110;//模拟业务未处理异常 75 | switch (t1.code) { 76 | //返回正确 77 | case 0: 78 | return t; 79 | case 10086: 80 | throw new TokenException("token is bad"); 81 | default: 82 | throw new IllegalArgumentException("I am big trouble"); 83 | } 84 | 85 | } else { 86 | return t; 87 | } 88 | 89 | } 90 | } 91 | 92 | @Override 93 | public void onSuccess(T t, Call call, Response response) { 94 | success(t, false); 95 | } 96 | 97 | @Override 98 | public void onCacheSuccess(T t, Call call) { 99 | super.onCacheSuccess(t, call); 100 | success(t, true); 101 | 102 | } 103 | 104 | @Override 105 | public void onParsedError(Error error, String message) { 106 | super.onParsedError(error, message); 107 | error(error, message); 108 | } 109 | 110 | /** 111 | * 通常实现以下回调即可-------------------------------------------------------------------------- 112 | */ 113 | 114 | /** 115 | * success 116 | * 117 | * @param t t 118 | * @param fromCache 是否来自缓存 119 | */ 120 | public abstract void success(T t, boolean fromCache); 121 | 122 | /** 123 | * error 124 | * 125 | * @param error 错误类型 126 | * @param message 错误详细文本 127 | */ 128 | public void error(Error error, String message) { 129 | } 130 | 131 | 132 | } -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/common/CommonRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package ricky.oknets.common; 3 | 4 | 5 | import ricky.oknet.utils.INoProguard; 6 | 7 | /** 8 | * @author ricky.yao on 2016/6/3. 9 | */ 10 | public class CommonRequest implements INoProguard { 11 | public String token; 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/common/CommonResponse.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.common; 2 | 3 | import ricky.oknet.utils.INoProguard; 4 | 5 | public class CommonResponse implements INoProguard { 6 | public int code; 7 | public String msg; 8 | public boolean error; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/exception/TokenException.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.exception; 2 | 3 | /** 4 | * @author Ricky.yao on 2016/5/16. 5 | */ 6 | public class TokenException extends Exception { 7 | public TokenException() { 8 | super("token失效"); 9 | } 10 | 11 | public TokenException(String m) { 12 | super(m); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/model/ApkModel.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class ApkModel implements Serializable { 6 | private static final long serialVersionUID = 2072893447591548402L; 7 | 8 | private String name; 9 | private String url; 10 | private String iconUrl; 11 | 12 | public ApkModel() { 13 | } 14 | 15 | public ApkModel(String name, String url, String iconUrl) { 16 | this.name = name; 17 | this.url = url; 18 | this.iconUrl = iconUrl; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | 29 | public String getUrl() { 30 | return url; 31 | } 32 | 33 | public void setUrl(String url) { 34 | this.url = url; 35 | } 36 | 37 | public String getIconUrl() { 38 | return iconUrl; 39 | } 40 | 41 | public void setIconUrl(String iconUrl) { 42 | this.iconUrl = iconUrl; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/model/LzyResponse.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * ================================================ 7 | * 作 者:jeasonlzy(廖子尧)Github地址:https://github.com/jeasonlzy 8 | * 版 本:1.0 9 | * 创建日期:16/9/28 10 | * 描 述: 11 | * 修订历史: 12 | * ================================================ 13 | */ 14 | public class LzyResponse implements Serializable { 15 | 16 | private static final long serialVersionUID = 5213230387175987834L; 17 | 18 | public int code; 19 | public String msg; 20 | public T data; 21 | } -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/model/NewsModel.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | * ================================================ 8 | * 作 者:jeasonlzy(廖子尧)Github地址:https://github.com/jeasonlzy 9 | * 版 本:1.0 10 | * 创建日期:16/9/1 11 | * 描 述: 12 | * 修订历史: 13 | * ================================================ 14 | */ 15 | public class NewsModel implements Serializable { 16 | 17 | private static final long serialVersionUID = 6753210234564872868L; 18 | 19 | public PageBean pagebean; 20 | public int ret_code; 21 | 22 | public static class PageBean implements Serializable { 23 | private static final long serialVersionUID = -7782857008135312889L; 24 | 25 | public int allNum; 26 | public int allPages; 27 | public int currentPage; 28 | public int maxResult; 29 | public List contentlist; 30 | } 31 | 32 | public static class ContentList implements Serializable { 33 | private static final long serialVersionUID = -7041713994407568209L; 34 | 35 | public String channelId; 36 | public String channelName; 37 | public String content; 38 | public String desc; 39 | public String html; 40 | public String link; 41 | public String nid; 42 | public String pubDate; 43 | public int sentiment_display; 44 | public String source; 45 | public String title; 46 | public List imageurls; 47 | } 48 | 49 | public static class NewsImage implements Serializable { 50 | private static final long serialVersionUID = -7441255403568397400L; 51 | 52 | public int width; 53 | public int height; 54 | public String url; 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/model/NewsResponse.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * ================================================ 7 | * 作 者:jeasonlzy(廖子尧)Github地址:https://github.com/jeasonlzy 8 | * 版 本:1.0 9 | * 创建日期:16/9/29 10 | * 描 述: 11 | * 修订历史: 12 | * ================================================ 13 | */ 14 | public class NewsResponse implements Serializable { 15 | 16 | private static final long serialVersionUID = -686453405647539973L; 17 | 18 | public String showapi_res_error; 19 | public int showapi_res_code; 20 | public T showapi_res_body; 21 | } -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/model/RequestBean.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.model; 2 | 3 | import ricky.oknets.common.CommonRequest; 4 | 5 | /** 6 | * @author ricky.yao on 2016/6/2. 7 | */ 8 | public class RequestBean extends CommonRequest { 9 | 10 | /** 11 | * userId : 34461 12 | * createAt : 0 13 | * size : 100 14 | */ 15 | 16 | public String userId = "34461"; 17 | public int createAt = 0; 18 | public int size = 100; 19 | 20 | 21 | public String updateAt; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/model/ServerModel.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * ================================================ 7 | * 作 者:jeasonlzy(廖子尧) 8 | * 版 本:1.0 9 | * 创建日期:2016/4/7 10 | * 描 述:我的Github地址 https://github.com/jeasonlzy 11 | * 修订历史: 12 | * ================================================ 13 | */ 14 | public class ServerModel implements Serializable { 15 | private static final long serialVersionUID = -828322761336296999L; 16 | 17 | public String method; 18 | public String ip; 19 | public String url; 20 | public String des; 21 | public String upload; 22 | public Author author; 23 | 24 | public class Author implements Serializable { 25 | private static final long serialVersionUID = 2701611773813762723L; 26 | 27 | public String name; 28 | public String fullname; 29 | public String github; 30 | public String address; 31 | public String qq; 32 | public String email; 33 | public String des; 34 | 35 | @Override 36 | public String toString() { 37 | return "Author{" + 38 | "name='" + name + '\'' + 39 | ", fullname='" + fullname + '\'' + 40 | ", github='" + github + '\'' + 41 | ", address='" + address + '\'' + 42 | ", qq='" + qq + '\'' + 43 | ", email='" + email + '\'' + 44 | ", des='" + des + '\'' + 45 | '}'; 46 | } 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "ServerModel{" + 52 | "method='" + method + '\'' + 53 | ", ip='" + ip + '\'' + 54 | ", url='" + url + '\'' + 55 | ", des='" + des + '\'' + 56 | ", upload='" + upload + '\'' + 57 | ", author=" + author + 58 | '}'; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/model/SimpleResponse.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * ================================================ 7 | * 作 者:jeasonlzy(廖子尧)Github地址:https://github.com/jeasonlzy 8 | * 版 本:1.0 9 | * 创建日期:16/9/28 10 | * 描 述: 11 | * 修订历史: 12 | * ================================================ 13 | */ 14 | public class SimpleResponse implements Serializable { 15 | 16 | private static final long serialVersionUID = -1477609349345966116L; 17 | 18 | public int code; 19 | public String msg; 20 | 21 | public LzyResponse toLzyResponse() { 22 | LzyResponse lzyResponse = new LzyResponse(); 23 | lzyResponse.code = code; 24 | lzyResponse.msg = msg; 25 | return lzyResponse; 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/request/Request.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.request; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | import ricky.oknet.utils.INoProguard; 7 | import ricky.oknets.common.CommonRequest; 8 | import ricky.oknets.common.CommonResponse; 9 | 10 | public class Request { 11 | public static class Req extends CommonRequest { 12 | public long userId = 50087; 13 | public ReqItemClass reqItemClass = new ReqItemClass(); 14 | 15 | public static class ReqItemClass { 16 | public String name = "ricky"; 17 | public String sex = "man"; 18 | } 19 | } 20 | 21 | public static class Res extends CommonResponse { 22 | 23 | 24 | public DataBean data; 25 | 26 | 27 | public static class DataBean implements Serializable { 28 | 29 | public AuthorBean author; 30 | public String des; 31 | public String method; 32 | public String url; 33 | public String ip; 34 | 35 | public static class AuthorBean implements Serializable { 36 | 37 | public String des; 38 | public String email; 39 | public String address; 40 | public String name; 41 | public String github; 42 | public String qq; 43 | public String fullname; 44 | } 45 | } 46 | } 47 | 48 | public static class Res1 extends CommonResponse { 49 | 50 | 51 | public int data; 52 | 53 | 54 | public static class DataBean implements Serializable { 55 | 56 | public AuthorBean author; 57 | public String des; 58 | public String method; 59 | public String url; 60 | public String ip; 61 | 62 | public static class AuthorBean implements Serializable { 63 | 64 | public String des; 65 | public String email; 66 | public String address; 67 | public String name; 68 | public String github; 69 | public String qq; 70 | public String fullname; 71 | } 72 | } 73 | } 74 | 75 | public static class Res2 implements INoProguard { 76 | 77 | 78 | public boolean error; 79 | public List results; 80 | 81 | static class Item implements INoProguard { 82 | public String _id; 83 | public String createdAt; 84 | public String desc; 85 | public String publishedAt; 86 | public String source; 87 | public String type; 88 | public String url; 89 | public boolean used; 90 | public String who; 91 | } 92 | 93 | 94 | } 95 | public static class Res3 implements INoProguard { 96 | 97 | 98 | public String date; 99 | public List stories; 100 | public List top_stories; 101 | 102 | public static class StoriesBean implements INoProguard { 103 | public String ga_prefix; 104 | public int id; 105 | public String title; 106 | public int type; 107 | public boolean multipic; 108 | public List images; 109 | } 110 | 111 | public static class TopStoriesBean implements INoProguard { 112 | public String ga_prefix; 113 | public int id; 114 | public String image; 115 | public String title; 116 | public int type; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/utils/Api.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.utils; 2 | 3 | import ricky.oknet.retrofit.ApiProxyHandler; 4 | import ricky.oknet.utils.ApiHelper; 5 | import ricky.oknets.HttpApi; 6 | import ricky.oknets.common.CommonRequest; 7 | 8 | /** 9 | * @author ricky.yao on 2016/5/25. 10 | */ 11 | public class Api { 12 | 13 | public static HttpApi getApi() { 14 | return ApiHelper.get(HttpApi.class, new ApiProxyHandler.ICustomerJsonBean() { 15 | @Override 16 | public CommonRequest onInterceptRequest(CommonRequest commonRequest) { 17 | commonRequest.token = "1234567"; 18 | return commonRequest; 19 | } 20 | }); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/ricky/oknets/utils/MD5Utils.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.security.DigestInputStream; 6 | import java.security.MessageDigest; 7 | 8 | /** 9 | * MD5加密工具类 10 | */ 11 | public class MD5Utils { 12 | 13 | private MD5Utils() { 14 | } 15 | 16 | /** 17 | * 获取字符串的 MD5 18 | */ 19 | public static String encode(String str) { 20 | try { 21 | MessageDigest md5 = MessageDigest.getInstance("MD5"); 22 | md5.update(str.getBytes("UTF-8")); 23 | byte messageDigest[] = md5.digest(); 24 | StringBuilder hexString = new StringBuilder(); 25 | for (byte b : messageDigest) { 26 | hexString.append(String.format("%02X", b)); 27 | } 28 | return hexString.toString().toLowerCase(); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | return ""; 33 | } 34 | 35 | /** 36 | * 获取文件的 MD5 37 | */ 38 | public static String encode(File file) { 39 | try { 40 | MessageDigest messageDigest = MessageDigest.getInstance("MD5"); 41 | FileInputStream inputStream = new FileInputStream(file); 42 | DigestInputStream digestInputStream = new DigestInputStream(inputStream, messageDigest); 43 | //必须把文件读取完毕才能拿到md5 44 | byte[] buffer = new byte[4096]; 45 | while (digestInputStream.read(buffer) > -1) { 46 | } 47 | MessageDigest digest = digestInputStream.getMessageDigest(); 48 | digestInputStream.close(); 49 | byte[] md5 = digest.digest(); 50 | StringBuilder sb = new StringBuilder(); 51 | for (byte b : md5) { 52 | sb.append(String.format("%02X", b)); 53 | } 54 | return sb.toString().toLowerCase(); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | } 58 | return null; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vihuela/OKNet/108e5a08d69fb6225bc89163de048eceb23f8d3f/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vihuela/OKNet/108e5a08d69fb6225bc89163de048eceb23f8d3f/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vihuela/OKNet/108e5a08d69fb6225bc89163de048eceb23f8d3f/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vihuela/OKNet/108e5a08d69fb6225bc89163de048eceb23f8d3f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vihuela/OKNet/108e5a08d69fb6225bc89163de048eceb23f8d3f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | OKNet 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/ricky/oknets/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package ricky.oknets; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7' 10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | jcenter() 17 | } 18 | } 19 | task clean(type: Delete) { 20 | delete rootProject.buildDir 21 | } 22 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vihuela/OKNet/108e5a08d69fb6225bc89163de048eceb23f8d3f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Mar 10 23:26:45 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /oknet/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /oknet/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | apply plugin: 'com.jfrog.bintray' 4 | 5 | //gradlew bintrayUpload 6 | android { 7 | compileSdkVersion 25 8 | buildToolsVersion '25.0.0' 9 | 10 | defaultConfig { 11 | minSdkVersion 14 12 | targetSdkVersion 25 13 | versionCode 1 14 | versionName "1.0" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | lintOptions { 23 | abortOnError false 24 | } 25 | } 26 | 27 | version = "1.2.6" // 数据仓库依赖第三部分 28 | 29 | def siteUrl = 'https://github.com/vihuela/OKNet' 30 | def gitUrl = 'https://github.com/vihuela/OKNet.git' 31 | group = "com.ricky" // 数据仓库依赖第一部分 32 | 33 | install { 34 | repositories.mavenInstaller { 35 | pom { 36 | project { 37 | packaging 'aar' 38 | name 'OkNet For Android' // 项目描述 39 | url siteUrl 40 | licenses { 41 | license { 42 | name 'The Apache Software License, Version 2.0' 43 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 44 | } 45 | } 46 | developers { 47 | developer { 48 | id 'vihuela' // 开发者信息 49 | name 'Ricky Yao' // 开发者信息 50 | email 'lomoliger@hotmail.com' // 开发者信息 51 | } 52 | } 53 | scm { 54 | connection gitUrl 55 | developerConnection gitUrl 56 | url siteUrl 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | task sourcesJar(type: Jar) { 64 | from android.sourceSets.main.java.srcDirs 65 | classifier = 'sources' 66 | } 67 | 68 | task javadoc(type: Javadoc) { 69 | source = android.sourceSets.main.java.srcDirs 70 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 71 | } 72 | 73 | task javadocJar(type: Jar, dependsOn: javadoc) { 74 | classifier = 'javadoc' 75 | from javadoc.destinationDir 76 | } 77 | 78 | javadoc { 79 | options { 80 | encoding "UTF-8" 81 | charSet 'UTF-8' 82 | author true 83 | version true 84 | links "http://docs.oracle.com/javase/7/docs/api" 85 | title 'OkNet For Android' // 文档标题 86 | } 87 | } 88 | 89 | artifacts { 90 | // archives javadocJar 91 | archives sourcesJar 92 | } 93 | 94 | // 生成jar包 95 | task releaseJar(type: Copy) { 96 | from('build/intermediates/bundles/release') 97 | into('../lib') 98 | include('classes.jar') 99 | rename('classes.jar', 'oknet-' + version + '.jar') 100 | } 101 | 102 | Properties properties = new Properties() 103 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 104 | bintray { 105 | user = properties.getProperty("bintray.user") 106 | key = properties.getProperty("bintray.apikey") 107 | configurations = ['archives'] 108 | pkg { 109 | repo = "maven" 110 | name = "oknet" // 数据仓库依赖第二部分 111 | websiteUrl = siteUrl 112 | vcsUrl = gitUrl 113 | licenses = ["Apache-2.0"] 114 | publish = true 115 | } 116 | } 117 | 118 | 119 | 120 | 121 | dependencies { 122 | compile fileTree(dir: 'libs', include: ['*.jar']) 123 | compile 'com.squareup.okhttp3:okhttp:3.4.1' 124 | compile 'com.google.code.gson:gson:2.7' 125 | compile 'io.reactivex:rxjava:1.2.0' 126 | compile 'io.reactivex:rxandroid:1.2.1' 127 | } 128 | -------------------------------------------------------------------------------- /oknet/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/adapter/Call.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.adapter; 2 | 3 | 4 | import ricky.oknet.callback.AbsCallback; 5 | import ricky.oknet.model.Response; 6 | import ricky.oknet.request.BaseRequest; 7 | 8 | public interface Call { 9 | /** 同步执行 */ 10 | Response execute() throws Exception; 11 | 12 | /** 异步回调执行 */ 13 | void execute(AbsCallback callback); 14 | 15 | /** 是否已经执行 */ 16 | boolean isExecuted(); 17 | 18 | /** 取消 */ 19 | void cancel(); 20 | 21 | /** 是否取消 */ 22 | boolean isCanceled(); 23 | 24 | Call clone(); 25 | 26 | BaseRequest getBaseRequest(); 27 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/adapter/CallAdapter.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.adapter; 2 | 3 | public interface CallAdapter { 4 | 5 | /** call执行的代理方法 */ 6 | T adapt(Call call); 7 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/adapter/DefaultCallAdapter.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.adapter; 2 | 3 | public class DefaultCallAdapter implements CallAdapter> { 4 | 5 | public static DefaultCallAdapter create() { 6 | return new DefaultCallAdapter<>(); 7 | } 8 | 9 | @Override 10 | public Call adapt(Call call) { 11 | return (Call) call; 12 | } 13 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cache/CacheDao.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cache; 2 | 3 | import android.content.ContentValues; 4 | import android.database.Cursor; 5 | 6 | import java.util.List; 7 | 8 | class CacheDao extends DataBaseDao> { 9 | 10 | public CacheDao() { 11 | super(new CacheHelper()); 12 | } 13 | 14 | /** 根据key获取缓存 */ 15 | public CacheEntity get(String key) { 16 | String selection = CacheHelper.KEY + "=?"; 17 | String[] selectionArgs = new String[]{key}; 18 | List> cacheEntities = get(selection, selectionArgs); 19 | return cacheEntities.size() > 0 ? cacheEntities.get(0) : null; 20 | } 21 | 22 | /** 移除一个缓存 */ 23 | public boolean remove(String key) { 24 | String whereClause = CacheHelper.KEY + "=?"; 25 | String[] whereArgs = new String[]{key}; 26 | int delete = delete(whereClause, whereArgs); 27 | return delete > 0; 28 | } 29 | 30 | @Override 31 | public CacheEntity parseCursorToBean(Cursor cursor) { 32 | return CacheEntity.parseCursorToBean(cursor); 33 | } 34 | 35 | @Override 36 | public ContentValues getContentValues(CacheEntity cacheEntity) { 37 | return CacheEntity.getContentValues(cacheEntity); 38 | } 39 | 40 | @Override 41 | protected String getTableName() { 42 | return CacheHelper.TABLE_NAME; 43 | } 44 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cache/CacheEntity.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cache; 2 | 3 | import android.content.ContentValues; 4 | import android.database.Cursor; 5 | 6 | 7 | import java.io.ByteArrayInputStream; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | import java.io.ObjectInputStream; 11 | import java.io.ObjectOutputStream; 12 | import java.io.Serializable; 13 | 14 | import ricky.oknet.model.HttpHeaders; 15 | import ricky.oknet.utils.OkLogger; 16 | 17 | public class CacheEntity implements Serializable { 18 | 19 | private static final long serialVersionUID = -4337711009801627866L; 20 | 21 | public static final long CACHE_NEVER_EXPIRE = -1; //缓存永不过期 22 | 23 | private long id; 24 | private String key; 25 | private HttpHeaders responseHeaders; 26 | private T data; 27 | private long localExpire; 28 | 29 | //该变量不必保存到数据库,程序运行起来后会动态计算 30 | private boolean isExpire; 31 | 32 | public long getId() { 33 | return id; 34 | } 35 | 36 | public void setId(long id) { 37 | this.id = id; 38 | } 39 | 40 | public String getKey() { 41 | return key; 42 | } 43 | 44 | public void setKey(String key) { 45 | this.key = key; 46 | } 47 | 48 | public HttpHeaders getResponseHeaders() { 49 | return responseHeaders; 50 | } 51 | 52 | public void setResponseHeaders(HttpHeaders responseHeaders) { 53 | this.responseHeaders = responseHeaders; 54 | } 55 | 56 | public T getData() { 57 | return data; 58 | } 59 | 60 | public void setData(T data) { 61 | this.data = data; 62 | } 63 | 64 | public long getLocalExpire() { 65 | return localExpire; 66 | } 67 | 68 | public void setLocalExpire(long localExpire) { 69 | this.localExpire = localExpire; 70 | } 71 | 72 | public boolean isExpire() { 73 | return isExpire; 74 | } 75 | 76 | public void setExpire(boolean expire) { 77 | isExpire = expire; 78 | } 79 | 80 | /** 81 | * @param cacheTime 允许的缓存时间 82 | * @param baseTime 基准时间,小于当前时间视为过期 83 | * @return 是否过期 84 | */ 85 | public boolean checkExpire(CacheMode cacheMode, long cacheTime, long baseTime) { 86 | //304的默认缓存模式,设置缓存时间无效,需要依靠服务端的响应头控制 87 | if (cacheMode == CacheMode.DEFAULT) return getLocalExpire() < baseTime; 88 | if (cacheTime == CACHE_NEVER_EXPIRE) return false; 89 | return getLocalExpire() + cacheTime < baseTime; 90 | } 91 | 92 | public static ContentValues getContentValues(CacheEntity cacheEntity) { 93 | ContentValues values = new ContentValues(); 94 | values.put(CacheHelper.KEY, cacheEntity.getKey()); 95 | values.put(CacheHelper.LOCAL_EXPIRE, cacheEntity.getLocalExpire()); 96 | 97 | HttpHeaders headers = cacheEntity.getResponseHeaders(); 98 | ByteArrayOutputStream headerBAOS = null; 99 | ObjectOutputStream headerOOS = null; 100 | try { 101 | if (headers != null) { 102 | headerBAOS = new ByteArrayOutputStream(); 103 | headerOOS = new ObjectOutputStream(headerBAOS); 104 | headerOOS.writeObject(headers); 105 | headerOOS.flush(); 106 | byte[] headerData = headerBAOS.toByteArray(); 107 | values.put(CacheHelper.HEAD, headerData); 108 | } 109 | } catch (IOException e) { 110 | OkLogger.e(e); 111 | } finally { 112 | try { 113 | if (headerOOS != null) headerOOS.close(); 114 | if (headerBAOS != null) headerBAOS.close(); 115 | } catch (IOException e) { 116 | OkLogger.e(e); 117 | } 118 | } 119 | 120 | T data = cacheEntity.getData(); 121 | ByteArrayOutputStream dataBAOS = null; 122 | ObjectOutputStream dataOOS = null; 123 | try { 124 | if (data != null) { 125 | dataBAOS = new ByteArrayOutputStream(); 126 | dataOOS = new ObjectOutputStream(dataBAOS); 127 | dataOOS.writeObject(data); 128 | dataOOS.flush(); 129 | byte[] dataData = dataBAOS.toByteArray(); 130 | values.put(CacheHelper.DATA, dataData); 131 | } 132 | } catch (IOException e) { 133 | OkLogger.e(e); 134 | } finally { 135 | try { 136 | if (dataOOS != null) dataOOS.close(); 137 | if (dataBAOS != null) dataBAOS.close(); 138 | } catch (IOException e) { 139 | OkLogger.e(e); 140 | } 141 | } 142 | return values; 143 | } 144 | 145 | public static CacheEntity parseCursorToBean(Cursor cursor) { 146 | CacheEntity cacheEntity = new CacheEntity<>(); 147 | cacheEntity.setId(cursor.getInt(cursor.getColumnIndex(CacheHelper.ID))); 148 | cacheEntity.setKey(cursor.getString(cursor.getColumnIndex(CacheHelper.KEY))); 149 | cacheEntity.setLocalExpire(cursor.getLong(cursor.getColumnIndex(CacheHelper.LOCAL_EXPIRE))); 150 | 151 | byte[] headerData = cursor.getBlob(cursor.getColumnIndex(CacheHelper.HEAD)); 152 | ByteArrayInputStream headerBAIS = null; 153 | ObjectInputStream headerOIS = null; 154 | try { 155 | if (headerData != null) { 156 | headerBAIS = new ByteArrayInputStream(headerData); 157 | headerOIS = new ObjectInputStream(headerBAIS); 158 | Object header = headerOIS.readObject(); 159 | cacheEntity.setResponseHeaders((HttpHeaders) header); 160 | } 161 | } catch (Exception e) { 162 | OkLogger.e(e); 163 | } finally { 164 | try { 165 | if (headerOIS != null) headerOIS.close(); 166 | if (headerBAIS != null) headerBAIS.close(); 167 | } catch (IOException e) { 168 | OkLogger.e(e); 169 | } 170 | } 171 | 172 | byte[] dataData = cursor.getBlob(cursor.getColumnIndex(CacheHelper.DATA)); 173 | ByteArrayInputStream dataBAIS = null; 174 | ObjectInputStream dataOIS = null; 175 | try { 176 | if (dataData != null) { 177 | dataBAIS = new ByteArrayInputStream(dataData); 178 | dataOIS = new ObjectInputStream(dataBAIS); 179 | T data = (T) dataOIS.readObject(); 180 | cacheEntity.setData(data); 181 | } 182 | } catch (Exception e) { 183 | OkLogger.e(e); 184 | } finally { 185 | try { 186 | if (dataOIS != null) dataOIS.close(); 187 | if (dataBAIS != null) dataBAIS.close(); 188 | } catch (IOException e) { 189 | OkLogger.e(e); 190 | } 191 | } 192 | 193 | return cacheEntity; 194 | } 195 | 196 | @Override 197 | public String toString() { 198 | return "CacheEntity{" + 199 | "id=" + id + 200 | ", key='" + key + '\'' + 201 | ", responseHeaders=" + responseHeaders + 202 | ", data=" + data + 203 | ", localExpire=" + localExpire + 204 | '}'; 205 | } 206 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cache/CacheHelper.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cache; 2 | 3 | import android.database.sqlite.SQLiteDatabase; 4 | import android.database.sqlite.SQLiteOpenHelper; 5 | 6 | import ricky.oknet.OkGo; 7 | import ricky.oknet.utils.OkLogger; 8 | 9 | 10 | class CacheHelper extends SQLiteOpenHelper { 11 | 12 | public static final String DB_CACHE_NAME = "okgo_cache.db"; 13 | public static final int DB_CACHE_VERSION = 3; 14 | public static final String TABLE_NAME = "cache_table"; 15 | 16 | //表中的五个字段 17 | public static final String ID = "_id"; 18 | public static final String KEY = "key"; 19 | public static final String LOCAL_EXPIRE = "localExpire"; 20 | public static final String HEAD = "head"; 21 | public static final String DATA = "data"; 22 | 23 | //四条sql语句 24 | private static final String SQL_CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + // 25 | ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +// 26 | KEY + " VARCHAR, " +// 27 | LOCAL_EXPIRE + " INTEGER, " +// 28 | HEAD + " BLOB, " +// 29 | DATA + " BLOB)"; 30 | private static final String SQL_CREATE_UNIQUE_INDEX = "CREATE UNIQUE INDEX cache_unique_index ON " + TABLE_NAME + "(\"key\")"; 31 | private static final String SQL_DELETE_TABLE = "DROP TABLE " + TABLE_NAME; 32 | private static final String SQL_DELETE_UNIQUE_INDEX = "DROP INDEX cache_unique_index"; 33 | 34 | public CacheHelper() { 35 | super(OkGo.getContext(), DB_CACHE_NAME, null, DB_CACHE_VERSION); 36 | } 37 | 38 | @Override 39 | public void onCreate(SQLiteDatabase db) { 40 | db.beginTransaction(); 41 | try { 42 | db.execSQL(SQL_CREATE_TABLE); 43 | //建立key的唯一索引后,方便使用 replace 语句 44 | db.execSQL(SQL_CREATE_UNIQUE_INDEX); 45 | db.setTransactionSuccessful(); 46 | } catch (Exception e) { 47 | OkLogger.e(e); 48 | } finally { 49 | db.endTransaction(); 50 | } 51 | } 52 | 53 | @Override 54 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 55 | if (newVersion != oldVersion) { 56 | db.beginTransaction(); 57 | try { 58 | db.execSQL(SQL_DELETE_UNIQUE_INDEX); 59 | db.execSQL(SQL_DELETE_TABLE); 60 | db.execSQL(SQL_CREATE_TABLE); 61 | db.execSQL(SQL_CREATE_UNIQUE_INDEX); 62 | db.setTransactionSuccessful(); 63 | } catch (Exception e) { 64 | OkLogger.e(e); 65 | } finally { 66 | db.endTransaction(); 67 | } 68 | } 69 | } 70 | 71 | @Override 72 | public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 73 | onUpgrade(db, oldVersion, newVersion); 74 | } 75 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cache/CacheManager.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cache; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.locks.Lock; 5 | import java.util.concurrent.locks.ReentrantLock; 6 | 7 | public enum CacheManager { 8 | 9 | INSTANCE; 10 | 11 | private Lock mLock; 12 | private CacheDao cacheDao; 13 | 14 | CacheManager() { 15 | mLock = new ReentrantLock(); 16 | cacheDao = new CacheDao<>(); 17 | } 18 | 19 | /** 20 | * 获取缓存 21 | * 22 | * @param key 缓存的Key 23 | * @return 缓存的对象实体 24 | */ 25 | public CacheEntity get(String key) { 26 | mLock.lock(); 27 | try { 28 | return cacheDao.get(key); 29 | } finally { 30 | mLock.unlock(); 31 | } 32 | } 33 | 34 | /** 返回带泛型的对象,注意必须确保泛型和对象对应才不会发生类型转换异常 */ 35 | @SuppressWarnings("unchecked") 36 | public CacheEntity get(String key, Class clazz) { 37 | return (CacheEntity) get(key); 38 | } 39 | 40 | /** 41 | * 获取所有缓存 42 | * 43 | * @return 缓存的对象实体 44 | */ 45 | public List> getAll() { 46 | mLock.lock(); 47 | try { 48 | return cacheDao.getAll(); 49 | } finally { 50 | mLock.unlock(); 51 | } 52 | } 53 | 54 | /** 55 | * 更新缓存,没有就创建,有就替换 56 | * 57 | * @param key 缓存的key 58 | * @param entity 需要替换的的缓存 59 | * @return 被替换的缓存 60 | */ 61 | @SuppressWarnings("unchecked") 62 | public CacheEntity replace(String key, CacheEntity entity) { 63 | mLock.lock(); 64 | try { 65 | entity.setKey(key); 66 | cacheDao.replace((CacheEntity) entity); 67 | return entity; 68 | } finally { 69 | mLock.unlock(); 70 | } 71 | } 72 | 73 | /** 74 | * 移除缓存 75 | * 76 | * @param key 缓存的key 77 | * @return 是否移除成功 78 | */ 79 | public boolean remove(String key) { 80 | if (key == null) return true; 81 | mLock.lock(); 82 | try { 83 | return cacheDao.remove(key); 84 | } finally { 85 | mLock.unlock(); 86 | } 87 | } 88 | 89 | /** 90 | * 清空缓存 91 | * 92 | * @return 是否清空成功 93 | */ 94 | public boolean clear() { 95 | mLock.lock(); 96 | try { 97 | return cacheDao.deleteAll() > 0; 98 | } finally { 99 | mLock.unlock(); 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cache/CacheMode.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cache; 2 | 3 | public enum CacheMode { 4 | /** 按照HTTP协议的默认缓存规则,例如有304响应头时缓存 */ 5 | DEFAULT, 6 | 7 | /** 不使用缓存 */ 8 | NO_CACHE, 9 | 10 | /** 请求网络失败后,读取缓存 */ 11 | REQUEST_FAILED_READ_CACHE, 12 | 13 | /** 如果缓存不存在才请求网络,否则使用缓存 */ 14 | IF_NONE_CACHE_REQUEST, 15 | 16 | /** 先使用缓存,不管是否存在,仍然请求网络 */ 17 | FIRST_CACHE_THEN_REQUEST, 18 | } 19 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cache/DataBaseDao.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cache; 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 java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import ricky.oknet.utils.OkLogger; 13 | 14 | public abstract class DataBaseDao { 15 | 16 | private SQLiteOpenHelper helper; 17 | 18 | public DataBaseDao(SQLiteOpenHelper helper) { 19 | this.helper = helper; 20 | } 21 | 22 | protected final SQLiteDatabase openReader() { 23 | return helper.getReadableDatabase(); 24 | } 25 | 26 | protected final SQLiteDatabase openWriter() { 27 | return helper.getWritableDatabase(); 28 | } 29 | 30 | protected final void closeDatabase(SQLiteDatabase database, Cursor cursor) { 31 | if (cursor != null && !cursor.isClosed()) cursor.close(); 32 | if (database != null && database.isOpen()) database.close(); 33 | } 34 | 35 | /** 获取对应的表名 */ 36 | protected abstract String getTableName(); 37 | 38 | /** 需要数据库中有个 _id 的字段 */ 39 | public int count() { 40 | return countColumn("_id"); 41 | } 42 | 43 | /** 返回一列的总记录数量 */ 44 | public int countColumn(String columnName) { 45 | String sql = "SELECT COUNT(?) FROM " + getTableName(); 46 | SQLiteDatabase database = openReader(); 47 | Cursor cursor = null; 48 | try { 49 | database.beginTransaction(); 50 | cursor = database.rawQuery(sql, new String[]{columnName}); 51 | int count = 0; 52 | if (cursor.moveToNext()) { 53 | count = cursor.getInt(0); 54 | } 55 | database.setTransactionSuccessful(); 56 | return count; 57 | } catch (Exception e) { 58 | OkLogger.e(e); 59 | } finally { 60 | database.endTransaction(); 61 | closeDatabase(database, cursor); 62 | } 63 | return 0; 64 | } 65 | 66 | /** 删除所有数据 */ 67 | public int deleteAll() { 68 | return delete(null, null); 69 | } 70 | 71 | /** 根据条件删除数据库中的数据 */ 72 | public int delete(String whereClause, String[] whereArgs) { 73 | SQLiteDatabase database = openWriter(); 74 | try { 75 | database.beginTransaction(); 76 | int result = database.delete(getTableName(), whereClause, whereArgs); 77 | database.setTransactionSuccessful(); 78 | return result; 79 | } catch (Exception e) { 80 | OkLogger.e(e); 81 | } finally { 82 | database.endTransaction(); 83 | closeDatabase(database, null); 84 | } 85 | return 0; 86 | } 87 | 88 | /** 查询并返回所有对象的集合 */ 89 | public List getAll() { 90 | return get(null, null); 91 | } 92 | 93 | /** 按条件查询对象并返回集合 */ 94 | public List get(String selection, String[] selectionArgs) { 95 | return get(null, selection, selectionArgs, null, null, null, null); 96 | } 97 | 98 | /** 按条件查询对象并返回集合 */ 99 | public List get(String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) { 100 | SQLiteDatabase database = openReader(); 101 | List list = new ArrayList<>(); 102 | Cursor cursor = null; 103 | try { 104 | database.beginTransaction(); 105 | cursor = database.query(getTableName(), columns, selection, selectionArgs, groupBy, having, orderBy, limit); 106 | while (!cursor.isClosed() && cursor.moveToNext()) { 107 | list.add(parseCursorToBean(cursor)); 108 | } 109 | database.setTransactionSuccessful(); 110 | } catch (Exception e) { 111 | OkLogger.e(e); 112 | } finally { 113 | database.endTransaction(); 114 | closeDatabase(database, cursor); 115 | } 116 | return list; 117 | } 118 | 119 | /** 120 | * replace 语句有如下行为特点 121 | * 1. replace语句会删除原有的一条记录, 并且插入一条新的记录来替换原记录。 122 | * 2. 一般用replace语句替换一条记录的所有列, 如果在replace语句中没有指定某列, 在replace之后这列的值被置空 。 123 | * 3. replace语句根据主键的值确定被替换的是哪一条记录 124 | * 4. 如果执行replace语句时, 不存在要替换的记录, 那么就会插入一条新的记录。 125 | * 5. replace语句不能根据where子句来定位要被替换的记录 126 | * 6. 如果新插入的或替换的记录中, 有字段和表中的其他记录冲突, 那么会删除那条其他记录。 127 | */ 128 | public long replace(T t) { 129 | SQLiteDatabase database = openWriter(); 130 | try { 131 | database.beginTransaction(); 132 | long id = database.replace(getTableName(), null, getContentValues(t)); 133 | database.setTransactionSuccessful(); 134 | return id; 135 | } catch (Exception e) { 136 | OkLogger.e(e); 137 | } finally { 138 | database.endTransaction(); 139 | closeDatabase(database, null); 140 | } 141 | return 0; 142 | } 143 | 144 | /** 创建一条记录 */ 145 | public long create(T t) { 146 | SQLiteDatabase database = openWriter(); 147 | try { 148 | database.beginTransaction(); 149 | long id = database.insert(getTableName(), null, getContentValues(t)); 150 | database.setTransactionSuccessful(); 151 | return id; 152 | } catch (Exception e) { 153 | OkLogger.e(e); 154 | } finally { 155 | database.endTransaction(); 156 | closeDatabase(database, null); 157 | } 158 | return 0; 159 | } 160 | 161 | /** 更新一条记录 */ 162 | public int update(T t, String whereClause, String[] whereArgs) { 163 | SQLiteDatabase database = openWriter(); 164 | try { 165 | database.beginTransaction(); 166 | int count = database.update(getTableName(), getContentValues(t), whereClause, whereArgs); 167 | database.setTransactionSuccessful(); 168 | return count; 169 | } catch (Exception e) { 170 | OkLogger.e(e); 171 | } finally { 172 | database.endTransaction(); 173 | closeDatabase(database, null); 174 | } 175 | return 0; 176 | } 177 | 178 | /** 将Cursor解析成对应的JavaBean */ 179 | public abstract T parseCursorToBean(Cursor cursor); 180 | 181 | /** 需要替换的列 */ 182 | public abstract ContentValues getContentValues(T t); 183 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/callback/AbsCallback.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.callback; 2 | 3 | 4 | import okhttp3.Call; 5 | import okhttp3.Response; 6 | import ricky.oknet.convert.Converter; 7 | import ricky.oknet.exception.parser.ExceptionParseMgr; 8 | import ricky.oknet.exception.parser.ExceptionParser; 9 | import ricky.oknet.request.BaseRequest; 10 | import ricky.oknet.cache.CacheMode; 11 | import ricky.oknet.utils.Cons; 12 | import ricky.oknet.utils.Error; 13 | 14 | /** 15 | *

该类的回调具有如下顺序,虽然顺序写的很复杂,但是理解后,是很简单,并且合情合理的 16 | *

1.无缓存模式{@link CacheMode#NO_CACHE}
17 | * ---网络请求成功 onBefore -> convertSuccess -> onSuccess -> onAfter
18 | * ---网络请求失败 onBefore -> parseError -> onError -> onAfter
19 | *

2.默认缓存模式,遵循304头{@link CacheMode#DEFAULT}
20 | * ---网络请求成功,服务端返回非304 onBefore -> convertSuccess -> onSuccess -> onAfter
21 | * ---网络请求成功服务端返回304 onBefore -> onCacheSuccess -> onAfter
22 | * ---网络请求失败 onBefore -> parseError -> onError -> onAfter
23 | *

3.请求网络失败后读取缓存{@link CacheMode#REQUEST_FAILED_READ_CACHE}
24 | * ---网络请求成功,不读取缓存 onBefore -> convertSuccess -> onSuccess -> onAfter
25 | * ---网络请求失败,读取缓存成功 onBefore -> parseError -> onError -> onCacheSuccess -> onAfter
26 | * ---网络请求失败,读取缓存失败 onBefore -> parseError -> onError -> onCacheError -> onAfter
27 | *

4.如果缓存不存在才请求网络,否则使用缓存{@link CacheMode#IF_NONE_CACHE_REQUEST}
28 | * ---已经有缓存,不请求网络 onBefore -> onCacheSuccess -> onAfter
29 | * ---没有缓存请求网络成功 onBefore -> onCacheError -> convertSuccess -> onSuccess -> onAfter
30 | * ---没有缓存请求网络失败 onBefore -> onCacheError -> parseError -> onError -> onAfter
31 | *

5.先使用缓存,不管是否存在,仍然请求网络{@link CacheMode#FIRST_CACHE_THEN_REQUEST}
32 | * ---无缓存时,网络请求成功 onBefore -> onCacheError -> convertSuccess -> onSuccess -> onAfter
33 | * ---无缓存时,网络请求失败 onBefore -> onCacheError -> parseError -> onError -> onAfter
34 | * ---有缓存时,网络请求成功 onBefore -> onCacheSuccess -> convertSuccess -> onSuccess -> onAfter
35 | * ---有缓存时,网络请求失败 onBefore -> onCacheSuccess -> parseError -> onError -> onAfter
36 | */ 37 | public abstract class AbsCallback implements Converter { 38 | 39 | /** 请求网络开始前,UI线程 */ 40 | public void onBefore(BaseRequest request) { 41 | } 42 | 43 | /** 对返回数据进行操作的回调, UI线程 */ 44 | public abstract void onSuccess(T t, Call call, Response response); 45 | 46 | /** 缓存成功的回调,UI线程 */ 47 | public void onCacheSuccess(T t, Call call) { 48 | } 49 | 50 | /** 请求失败,响应错误,数据解析错误等,都会回调该方法, UI线程 */ 51 | public void onError(Call call, Response response, Throwable e) { 52 | 53 | //使用错误解析器分发错误 54 | ExceptionParseMgr.Instance.parseException(e, new ExceptionParser.IHandler() { 55 | @Override 56 | public void onHandler(Error error, String message) { 57 | onParsedError(error, message); 58 | } 59 | }); 60 | } 61 | 62 | /**添加自定义异常解析器,可参考#NetExceptionParser的实现*/ 63 | final protected void addExceptionParser(ExceptionParser parser) { 64 | ExceptionParseMgr.Instance.addParse(parser); 65 | } 66 | 67 | /**经过解析器分发之后的错误*/ 68 | public void onParsedError(Error error, String message){ 69 | 70 | } 71 | 72 | /** 缓存失败的回调,UI线程 */ 73 | public void onCacheError(Call call, Exception e) { 74 | } 75 | 76 | /** 网络失败结束之前的回调 */ 77 | public void parseError(Call call, Exception e) { 78 | } 79 | 80 | /** 请求网络结束后,UI线程 */ 81 | public void onAfter(T t, Exception e) { 82 | if (e != null) e.printStackTrace(); 83 | } 84 | 85 | /** 86 | * Post执行上传过程中的进度回调,get请求不回调,UI线程 87 | * 88 | * @param currentSize 当前上传的字节数 89 | * @param totalSize 总共需要上传的字节数 90 | * @param progress 当前上传的进度 91 | * @param networkSpeed 当前上传的速度 字节/秒 92 | */ 93 | public void upProgress(long currentSize, long totalSize, float progress, long networkSpeed) { 94 | } 95 | 96 | /** 97 | * 执行下载过程中的进度回调,UI线程 98 | * 99 | * @param currentSize 当前下载的字节数 100 | * @param totalSize 总共需要下载的字节数 101 | * @param progress 当前下载的进度 102 | * @param networkSpeed 当前下载的速度 字节/秒 103 | */ 104 | public void downloadProgress(long currentSize, long totalSize, float progress, long networkSpeed) { 105 | } 106 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/callback/AbsCallbackWrapper.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.callback; 2 | 3 | import okhttp3.Call; 4 | import okhttp3.Response; 5 | 6 | public class AbsCallbackWrapper extends AbsCallback { 7 | @Override 8 | public T convertSuccess(Response value) throws Exception { 9 | value.close(); 10 | return (T) value; 11 | } 12 | 13 | @Override 14 | public void onSuccess(T t, Call call, Response response) { 15 | } 16 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/callback/BitmapCallback.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.callback; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | 6 | import okhttp3.Response; 7 | import ricky.oknet.convert.BitmapConvert; 8 | 9 | public abstract class BitmapCallback extends AbsCallback { 10 | 11 | @Override 12 | public Bitmap convertSuccess(Response response) throws Exception { 13 | Bitmap bitmap = BitmapConvert.create().convertSuccess(response); 14 | response.close(); 15 | return bitmap; 16 | } 17 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/callback/FileCallback.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.callback; 2 | 3 | 4 | import java.io.File; 5 | 6 | import okhttp3.Response; 7 | import ricky.oknet.convert.FileConvert; 8 | 9 | public abstract class FileCallback extends AbsCallback { 10 | 11 | private FileConvert convert; //文件转换类 12 | 13 | public FileCallback() { 14 | this(null); 15 | } 16 | 17 | public FileCallback(String destFileName) { 18 | this(null, destFileName); 19 | } 20 | 21 | public FileCallback(String destFileDir, String destFileName) { 22 | convert = new FileConvert(destFileDir, destFileName); 23 | convert.setCallback(this); 24 | } 25 | 26 | @Override 27 | public File convertSuccess(Response response) throws Exception { 28 | File file = convert.convertSuccess(response); 29 | response.close(); 30 | return file; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/callback/StringCallback.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.callback; 2 | 3 | 4 | import okhttp3.Response; 5 | import ricky.oknet.convert.StringConvert; 6 | 7 | public abstract class StringCallback extends AbsCallback { 8 | 9 | @Override 10 | public String convertSuccess(Response response) throws Exception { 11 | String s = StringConvert.create().convertSuccess(response); 12 | response.close(); 13 | return s; 14 | } 15 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/convert/BitmapConvert.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.convert; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | 6 | import okhttp3.Response; 7 | 8 | public class BitmapConvert implements Converter { 9 | 10 | public static BitmapConvert create() { 11 | return BitmapConvert.ConvertHolder.convert; 12 | } 13 | 14 | private static class ConvertHolder { 15 | private static BitmapConvert convert = new BitmapConvert(); 16 | } 17 | 18 | @Override 19 | public Bitmap convertSuccess(Response value) throws Exception { 20 | return BitmapFactory.decodeStream(value.body().byteStream()); 21 | } 22 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/convert/Converter.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.convert; 2 | 3 | import okhttp3.Response; 4 | 5 | public interface Converter { 6 | 7 | /** 8 | * 拿到响应后,将数据转换成需要的格式,子线程中执行,可以是耗时操作 9 | * 10 | * @param response 需要转换的对象 11 | * @return 转换后的结果 12 | * @throws Exception 转换过程发生的异常 13 | */ 14 | T convertSuccess(Response response) throws Exception; 15 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/convert/FileConvert.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.convert; 2 | 3 | import android.os.Environment; 4 | import android.text.TextUtils; 5 | 6 | 7 | import java.io.File; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | 12 | import okhttp3.Response; 13 | import ricky.oknet.OkGo; 14 | import ricky.oknet.callback.AbsCallback; 15 | import ricky.oknet.utils.HttpUtils; 16 | import ricky.oknet.utils.OkLogger; 17 | 18 | public class FileConvert implements Converter { 19 | 20 | public static final String DM_TARGET_FOLDER = File.separator + "download" + File.separator; //下载目标文件夹 21 | 22 | private String destFileDir; //目标文件存储的文件夹路径 23 | private String destFileName; //目标文件存储的文件名 24 | private AbsCallback callback; //下载回调 25 | 26 | public FileConvert() { 27 | this(null); 28 | } 29 | 30 | public FileConvert(String destFileName) { 31 | this(Environment.getExternalStorageDirectory() + DM_TARGET_FOLDER, destFileName); 32 | } 33 | 34 | public FileConvert(String destFileDir, String destFileName) { 35 | this.destFileDir = destFileDir; 36 | this.destFileName = destFileName; 37 | } 38 | 39 | public void setCallback(AbsCallback callback) { 40 | this.callback = callback; 41 | } 42 | 43 | @Override 44 | public File convertSuccess(Response value) throws Exception { 45 | if (TextUtils.isEmpty(destFileDir)) destFileDir = Environment.getExternalStorageDirectory() + DM_TARGET_FOLDER; 46 | if (TextUtils.isEmpty(destFileName)) destFileName = HttpUtils.getNetFileName(value, value.request().url().toString()); 47 | 48 | File dir = new File(destFileDir); 49 | if (!dir.exists()) dir.mkdirs(); 50 | File file = new File(dir, destFileName); 51 | if (file.exists()) file.delete(); 52 | 53 | long lastRefreshUiTime = 0; //最后一次刷新的时间 54 | long lastWriteBytes = 0; //最后一次写入字节数据 55 | 56 | InputStream is = null; 57 | byte[] buf = new byte[2048]; 58 | FileOutputStream fos = null; 59 | try { 60 | is = value.body().byteStream(); 61 | final long total = value.body().contentLength(); 62 | long sum = 0; 63 | int len; 64 | fos = new FileOutputStream(file); 65 | while ((len = is.read(buf)) != -1) { 66 | sum += len; 67 | fos.write(buf, 0, len); 68 | 69 | //下载进度回调 70 | if (callback != null) { 71 | final long finalSum = sum; 72 | long curTime = System.currentTimeMillis(); 73 | //每200毫秒刷新一次数据 74 | if (curTime - lastRefreshUiTime >= OkGo.REFRESH_TIME || finalSum == total) { 75 | //计算下载速度 76 | long diffTime = (curTime - lastRefreshUiTime) / 1000; 77 | if (diffTime == 0) diffTime += 1; 78 | long diffBytes = finalSum - lastWriteBytes; 79 | final long networkSpeed = diffBytes / diffTime; 80 | OkGo.getInstance().getDelivery().post(new Runnable() { 81 | @Override 82 | public void run() { 83 | callback.downloadProgress(finalSum, total, finalSum * 1.0f / total, networkSpeed); //进度回调的方法 84 | } 85 | }); 86 | 87 | lastRefreshUiTime = System.currentTimeMillis(); 88 | lastWriteBytes = finalSum; 89 | } 90 | } 91 | } 92 | fos.flush(); 93 | return file; 94 | } finally { 95 | try { 96 | if (is != null) is.close(); 97 | } catch (IOException e) { 98 | OkLogger.e(e); 99 | } 100 | try { 101 | if (fos != null) fos.close(); 102 | } catch (IOException e) { 103 | OkLogger.e(e); 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/convert/StringConvert.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.convert; 2 | 3 | import okhttp3.Response; 4 | 5 | public class StringConvert implements Converter { 6 | 7 | public static StringConvert create() { 8 | return ConvertHolder.convert; 9 | } 10 | 11 | private static class ConvertHolder { 12 | private static StringConvert convert = new StringConvert(); 13 | } 14 | 15 | @Override 16 | public String convertSuccess(Response value) throws Exception { 17 | return value.body().string(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cookie/CookieJarImpl.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cookie; 2 | 3 | 4 | import java.util.List; 5 | 6 | import okhttp3.Cookie; 7 | import okhttp3.CookieJar; 8 | import okhttp3.HttpUrl; 9 | import ricky.oknet.cookie.store.CookieStore; 10 | 11 | public class CookieJarImpl implements CookieJar { 12 | 13 | private CookieStore cookieStore; 14 | 15 | public CookieJarImpl(CookieStore cookieStore) { 16 | if (cookieStore == null) { 17 | throw new IllegalArgumentException("cookieStore can not be null!"); 18 | } 19 | this.cookieStore = cookieStore; 20 | } 21 | 22 | @Override 23 | public synchronized void saveFromResponse(HttpUrl url, List cookies) { 24 | cookieStore.saveCookie(url, cookies); 25 | } 26 | 27 | @Override 28 | public synchronized List loadForRequest(HttpUrl url) { 29 | return cookieStore.loadCookie(url); 30 | } 31 | 32 | public CookieStore getCookieStore() { 33 | return cookieStore; 34 | } 35 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cookie/store/CookieStore.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cookie.store; 2 | 3 | import java.util.List; 4 | 5 | import okhttp3.Cookie; 6 | import okhttp3.HttpUrl; 7 | 8 | public interface CookieStore { 9 | 10 | /** 保存url对应所有cookie */ 11 | void saveCookie(HttpUrl url, List cookie); 12 | 13 | /** 保存url对应所有cookie */ 14 | void saveCookie(HttpUrl url, Cookie cookie); 15 | 16 | /** 加载url所有的cookie */ 17 | List loadCookie(HttpUrl url); 18 | 19 | /** 获取当前所有保存的cookie */ 20 | List getAllCookie(); 21 | 22 | /** 获取当前url对应的所有的cookie */ 23 | List getCookie(HttpUrl url); 24 | 25 | /** 根据url和cookie移除对应的cookie */ 26 | boolean removeCookie(HttpUrl url, Cookie cookie); 27 | 28 | /** 根据url移除所有的cookie */ 29 | boolean removeCookie(HttpUrl url); 30 | 31 | /** 移除所有的cookie */ 32 | boolean removeAllCookie(); 33 | } 34 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cookie/store/MemoryCookieStore.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cookie.store; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | import okhttp3.Cookie; 9 | import okhttp3.HttpUrl; 10 | 11 | public class MemoryCookieStore implements CookieStore { 12 | 13 | private final HashMap> memoryCookies = new HashMap<>(); 14 | 15 | @Override 16 | public synchronized void saveCookie(HttpUrl url, List cookies) { 17 | List oldCookies = memoryCookies.get(url.host()); 18 | List needRemove = new ArrayList<>(); 19 | for (Cookie newCookie : cookies) { 20 | for (Cookie oldCookie : oldCookies) { 21 | if (newCookie.name().equals(oldCookie.name())) { 22 | needRemove.add(oldCookie); 23 | } 24 | } 25 | } 26 | oldCookies.removeAll(needRemove); 27 | oldCookies.addAll(cookies); 28 | } 29 | 30 | @Override 31 | public synchronized void saveCookie(HttpUrl url, Cookie cookie) { 32 | List cookies = memoryCookies.get(url.host()); 33 | List needRemove = new ArrayList<>(); 34 | for (Cookie item : cookies) { 35 | if (cookie.name().equals(item.name())) { 36 | needRemove.add(item); 37 | } 38 | } 39 | cookies.removeAll(needRemove); 40 | cookies.add(cookie); 41 | } 42 | 43 | @Override 44 | public synchronized List loadCookie(HttpUrl url) { 45 | List cookies = memoryCookies.get(url.host()); 46 | if (cookies == null) { 47 | cookies = new ArrayList<>(); 48 | memoryCookies.put(url.host(), cookies); 49 | } 50 | return cookies; 51 | } 52 | 53 | @Override 54 | public synchronized List getAllCookie() { 55 | List cookies = new ArrayList<>(); 56 | Set httpUrls = memoryCookies.keySet(); 57 | for (String url : httpUrls) { 58 | cookies.addAll(memoryCookies.get(url)); 59 | } 60 | return cookies; 61 | } 62 | 63 | @Override 64 | public List getCookie(HttpUrl url) { 65 | List cookies = new ArrayList<>(); 66 | List urlCookies = memoryCookies.get(url.host()); 67 | if (urlCookies != null) cookies.addAll(urlCookies); 68 | return cookies; 69 | } 70 | 71 | @Override 72 | public synchronized boolean removeCookie(HttpUrl url, Cookie cookie) { 73 | List cookies = memoryCookies.get(url.host()); 74 | return (cookie != null) && cookies.remove(cookie); 75 | } 76 | 77 | @Override 78 | public synchronized boolean removeCookie(HttpUrl url) { 79 | return memoryCookies.remove(url.host()) != null; 80 | } 81 | 82 | @Override 83 | public synchronized boolean removeAllCookie() { 84 | memoryCookies.clear(); 85 | return true; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/cookie/store/SerializableHttpCookie.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.cookie.store; 2 | 3 | import java.io.IOException; 4 | import java.io.ObjectInputStream; 5 | import java.io.ObjectOutputStream; 6 | import java.io.Serializable; 7 | 8 | import okhttp3.Cookie; 9 | 10 | public class SerializableHttpCookie implements Serializable { 11 | private static final long serialVersionUID = 6374381323722046732L; 12 | 13 | private transient final Cookie cookie; 14 | private transient Cookie clientCookie; 15 | 16 | public SerializableHttpCookie(Cookie cookie) { 17 | this.cookie = cookie; 18 | } 19 | 20 | public Cookie getCookie() { 21 | Cookie bestCookie = cookie; 22 | if (clientCookie != null) { 23 | bestCookie = clientCookie; 24 | } 25 | return bestCookie; 26 | } 27 | 28 | private void writeObject(ObjectOutputStream out) throws IOException { 29 | out.writeObject(cookie.name()); 30 | out.writeObject(cookie.value()); 31 | out.writeLong(cookie.expiresAt()); 32 | out.writeObject(cookie.domain()); 33 | out.writeObject(cookie.path()); 34 | out.writeBoolean(cookie.secure()); 35 | out.writeBoolean(cookie.httpOnly()); 36 | out.writeBoolean(cookie.hostOnly()); 37 | out.writeBoolean(cookie.persistent()); 38 | } 39 | 40 | private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 41 | String name = (String) in.readObject(); 42 | String value = (String) in.readObject(); 43 | long expiresAt = in.readLong(); 44 | String domain = (String) in.readObject(); 45 | String path = (String) in.readObject(); 46 | boolean secure = in.readBoolean(); 47 | boolean httpOnly = in.readBoolean(); 48 | boolean hostOnly = in.readBoolean(); 49 | boolean persistent = in.readBoolean(); 50 | Cookie.Builder builder = new Cookie.Builder(); 51 | builder = builder.name(name); 52 | builder = builder.value(value); 53 | builder = builder.expiresAt(expiresAt); 54 | builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain); 55 | builder = builder.path(path); 56 | builder = secure ? builder.secure() : builder; 57 | builder = httpOnly ? builder.httpOnly() : builder; 58 | clientCookie = builder.build(); 59 | } 60 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/exception/OkGoException.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.exception; 2 | 3 | public class OkGoException extends Exception { 4 | 5 | public static OkGoException INSTANCE(String msg) { 6 | return new OkGoException(msg); 7 | } 8 | 9 | public OkGoException() { 10 | super(); 11 | } 12 | 13 | public OkGoException(String detailMessage) { 14 | super(detailMessage); 15 | } 16 | 17 | public OkGoException(String detailMessage, Throwable throwable) { 18 | super(detailMessage, throwable); 19 | } 20 | 21 | public OkGoException(Throwable throwable) { 22 | super(throwable); 23 | } 24 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/exception/ServerException.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.exception; 2 | 3 | public class ServerException extends Exception { 4 | 5 | public static ServerException INSTANCE(String msg) { 6 | return new ServerException(msg); 7 | } 8 | public ServerException(String detailMessage) { 9 | super(detailMessage); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/exception/parser/ExceptionParseMgr.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.exception.parser; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public enum ExceptionParseMgr { 7 | Instance; 8 | 9 | private List parsers = new ArrayList<>(); 10 | 11 | ExceptionParseMgr() { 12 | 13 | resetParses(); 14 | connectionParse(); 15 | } 16 | 17 | private void resetParses() { 18 | parsers.add(new NetExceptionParser()); 19 | parsers.add(new ServerExceptionParser()); 20 | parsers.add(new InternalExceptionParser()); 21 | parsers.add(new UnknowExceptionParser());//last item must be UnknowExceptionParser 22 | } 23 | 24 | private void connectionParse() { 25 | for (int i = 0; i < parsers.size(); i++) { 26 | 27 | final ExceptionParser item = parsers.get(i); 28 | 29 | if (i + 1 < parsers.size()) { 30 | item.setNextParser(parsers.get(i + 1)); 31 | } 32 | } 33 | } 34 | 35 | public void parseException(Throwable e, ExceptionParser.IHandler iHandler) { 36 | 37 | parsers.get(0).handleException(e, iHandler); 38 | 39 | } 40 | 41 | public void addParse(ExceptionParser parser) { 42 | 43 | if (parser != null) { 44 | parsers.add(0, parser);//自定义异常优先 45 | connectionParse(); 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/exception/parser/ExceptionParser.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.exception.parser; 2 | 3 | 4 | import android.text.TextUtils; 5 | 6 | import ricky.oknet.utils.Error; 7 | 8 | public abstract class ExceptionParser { 9 | private ExceptionParser nextParser; 10 | 11 | public static String getMessageFromThrowable(Throwable e) { 12 | return !TextUtils.isEmpty(e.getMessage()) ? e.getMessage() : e.getClass().getSimpleName(); 13 | } 14 | 15 | void handleException(Throwable e, IHandler handler) { 16 | //first 17 | if (e != null && !handler(e, handler)) { 18 | //second 19 | if (e.getCause() != null && !handler(e.getCause(), handler)) { 20 | //third 21 | next(e, handler); 22 | } else { 23 | next(e, handler); 24 | } 25 | } 26 | } 27 | 28 | private void next(Throwable e, IHandler handler) { 29 | if (getNextParser() != null) getNextParser().handleException(e, handler); 30 | } 31 | 32 | /** 33 | * @return true is resume error 34 | */ 35 | protected abstract boolean handler(Throwable e, IHandler handler); 36 | 37 | private ExceptionParser getNextParser() { 38 | return nextParser; 39 | } 40 | 41 | void setNextParser(ExceptionParser nextParser) { 42 | this.nextParser = nextParser; 43 | } 44 | 45 | public interface IHandler { 46 | void onHandler(Error error, String message); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/exception/parser/InternalExceptionParser.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.exception.parser; 2 | 3 | import com.google.gson.JsonParseException; 4 | 5 | import org.json.JSONException; 6 | 7 | import ricky.oknet.utils.Error; 8 | 9 | /** 10 | * only json error check 11 | */ 12 | class InternalExceptionParser extends ExceptionParser { 13 | 14 | 15 | @Override 16 | protected boolean handler(Throwable e, IHandler handler) { 17 | 18 | if (NumberFormatException.class.isAssignableFrom(e.getClass()) || 19 | JsonParseException.class.isAssignableFrom(e.getClass()) || 20 | com.google.gson.JsonSyntaxException.class.isAssignableFrom(e.getClass()) || 21 | JSONException.class.isAssignableFrom(e.getClass())) { 22 | handler.onHandler(Error.Internal, getMessageFromThrowable(e)); 23 | return true; 24 | } 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/exception/parser/NetExceptionParser.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.exception.parser; 2 | 3 | import java.net.SocketException; 4 | import java.net.SocketTimeoutException; 5 | import java.net.UnknownHostException; 6 | 7 | import ricky.oknet.utils.Cons; 8 | import ricky.oknet.utils.Error; 9 | 10 | class NetExceptionParser extends ExceptionParser { 11 | 12 | 13 | @Override 14 | protected boolean handler(Throwable e, IHandler handler) { 15 | String s = getMessageFromThrowable(e); 16 | if (Cons.IO_EXCEPTION.equalsIgnoreCase(s) || Cons.SOCKET_EXCEPTION.equalsIgnoreCase(s)) { 17 | //cancel request 18 | return true; 19 | } 20 | if (UnknownHostException.class.isAssignableFrom(e.getClass()) || 21 | SocketException.class.isAssignableFrom(e.getClass()) || 22 | SocketTimeoutException.class.isAssignableFrom(e.getClass())) { 23 | handler.onHandler(Error.NetWork, s); 24 | return true; 25 | } 26 | return false; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/exception/parser/ServerExceptionParser.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.exception.parser; 2 | 3 | import ricky.oknet.exception.ServerException; 4 | import ricky.oknet.utils.Error; 5 | 6 | 7 | class ServerExceptionParser extends ExceptionParser { 8 | 9 | @Override 10 | protected boolean handler(Throwable e, IHandler handler) { 11 | if (ServerException.class.isAssignableFrom(e.getClass())) { 12 | handler.onHandler(Error.Server, getMessageFromThrowable(e)); 13 | return true; 14 | } 15 | return false; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/exception/parser/UnknowExceptionParser.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.exception.parser; 2 | 3 | import ricky.oknet.utils.Error; 4 | 5 | class UnknowExceptionParser extends ExceptionParser { 6 | 7 | /** 8 | * must return true 9 | */ 10 | @Override 11 | protected boolean handler(Throwable e, IHandler handler) { 12 | handler.onHandler(Error.UnKnow, getMessageFromThrowable(e)); 13 | return true; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/https/HttpsUtils.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.https; 2 | 3 | 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.security.KeyManagementException; 7 | import java.security.KeyStore; 8 | import java.security.NoSuchAlgorithmException; 9 | import java.security.cert.Certificate; 10 | import java.security.cert.CertificateException; 11 | import java.security.cert.CertificateFactory; 12 | import java.security.cert.X509Certificate; 13 | 14 | import javax.net.ssl.HostnameVerifier; 15 | import javax.net.ssl.KeyManager; 16 | import javax.net.ssl.KeyManagerFactory; 17 | import javax.net.ssl.SSLContext; 18 | import javax.net.ssl.SSLSession; 19 | import javax.net.ssl.SSLSocketFactory; 20 | import javax.net.ssl.TrustManager; 21 | import javax.net.ssl.TrustManagerFactory; 22 | import javax.net.ssl.X509TrustManager; 23 | 24 | import ricky.oknet.utils.OkLogger; 25 | 26 | public class HttpsUtils { 27 | 28 | public static class SSLParams { 29 | public SSLSocketFactory sSLSocketFactory; 30 | public X509TrustManager trustManager; 31 | } 32 | 33 | public static SSLParams getSslSocketFactory(X509TrustManager trustManager, InputStream bksFile, String password, InputStream[] certificates) { 34 | SSLParams sslParams = new SSLParams(); 35 | try { 36 | KeyManager[] keyManagers = prepareKeyManager(bksFile, password); 37 | TrustManager[] trustManagers = prepareTrustManager(certificates); 38 | X509TrustManager manager; 39 | if (trustManager != null) { 40 | //优先使用用户自定义的TrustManager 41 | manager = trustManager; 42 | } else if (trustManagers != null) { 43 | //然后使用默认的TrustManager 44 | manager = chooseTrustManager(trustManagers); 45 | } else { 46 | //否则使用不安全的TrustManager 47 | manager = UnSafeTrustManager; 48 | } 49 | // 创建TLS类型的SSLContext对象, that uses our TrustManager 50 | SSLContext sslContext = SSLContext.getInstance("TLS"); 51 | // 用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书 52 | // 第一个参数是授权的密钥管理器,用来授权验证,比如授权自签名的证书验证。第二个是被授权的证书管理器,用来验证服务器端的证书 53 | sslContext.init(keyManagers, new TrustManager[]{manager}, null); 54 | // 通过sslContext获取SSLSocketFactory对象 55 | sslParams.sSLSocketFactory = sslContext.getSocketFactory(); 56 | sslParams.trustManager = manager; 57 | return sslParams; 58 | } catch (NoSuchAlgorithmException e) { 59 | throw new AssertionError(e); 60 | } catch (KeyManagementException e) { 61 | throw new AssertionError(e); 62 | } 63 | } 64 | 65 | private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) { 66 | try { 67 | if (bksFile == null || password == null) return null; 68 | KeyStore clientKeyStore = KeyStore.getInstance("BKS"); 69 | clientKeyStore.load(bksFile, password.toCharArray()); 70 | KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 71 | kmf.init(clientKeyStore, password.toCharArray()); 72 | return kmf.getKeyManagers(); 73 | } catch (Exception e) { 74 | OkLogger.e(e); 75 | } 76 | return null; 77 | } 78 | 79 | private static TrustManager[] prepareTrustManager(InputStream... certificates) { 80 | if (certificates == null || certificates.length <= 0) return null; 81 | try { 82 | CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); 83 | // 创建一个默认类型的KeyStore,存储我们信任的证书 84 | KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 85 | keyStore.load(null); 86 | int index = 0; 87 | for (InputStream certStream : certificates) { 88 | String certificateAlias = Integer.toString(index++); 89 | // 证书工厂根据证书文件的流生成证书 cert 90 | Certificate cert = certificateFactory.generateCertificate(certStream); 91 | // 将 cert 作为可信证书放入到keyStore中 92 | keyStore.setCertificateEntry(certificateAlias, cert); 93 | try { 94 | if (certStream != null) certStream.close(); 95 | } catch (IOException e) { 96 | OkLogger.e(e); 97 | } 98 | } 99 | //我们创建一个默认类型的TrustManagerFactory 100 | TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 101 | //用我们之前的keyStore实例初始化TrustManagerFactory,这样tmf就会信任keyStore中的证书 102 | tmf.init(keyStore); 103 | //通过tmf获取TrustManager数组,TrustManager也会信任keyStore中的证书 104 | return tmf.getTrustManagers(); 105 | } catch (Exception e) { 106 | OkLogger.e(e); 107 | } 108 | return null; 109 | } 110 | 111 | private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) { 112 | for (TrustManager trustManager : trustManagers) { 113 | if (trustManager instanceof X509TrustManager) { 114 | return (X509TrustManager) trustManager; 115 | } 116 | } 117 | return null; 118 | } 119 | 120 | /** 121 | * 为了解决客户端不信任服务器数字证书的问题,网络上大部分的解决方案都是让客户端不对证书做任何检查, 122 | * 这是一种有很大安全漏洞的办法 123 | */ 124 | public static X509TrustManager UnSafeTrustManager = new X509TrustManager() { 125 | @Override 126 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 127 | } 128 | 129 | @Override 130 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 131 | } 132 | 133 | @Override 134 | public X509Certificate[] getAcceptedIssuers() { 135 | return new java.security.cert.X509Certificate[]{}; 136 | } 137 | }; 138 | 139 | /** 140 | * 此类是用于主机名验证的基接口。 在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配, 141 | * 则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。策略可以是基于证书的或依赖于其他验证方案。 142 | * 当验证 URL 主机名使用的默认规则失败时使用这些回调。如果主机名是可接受的,则返回 true 143 | */ 144 | public static HostnameVerifier UnSafeHostnameVerifier = new HostnameVerifier() { 145 | @Override 146 | public boolean verify(String hostname, SSLSession session) { 147 | return true; 148 | } 149 | }; 150 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/interceptor/HttpLoggingInterceptor.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.interceptor; 2 | 3 | 4 | import java.io.IOException; 5 | import java.nio.charset.Charset; 6 | import java.util.concurrent.TimeUnit; 7 | import java.util.logging.Logger; 8 | 9 | import okhttp3.Connection; 10 | import okhttp3.Headers; 11 | import okhttp3.Interceptor; 12 | import okhttp3.MediaType; 13 | import okhttp3.Protocol; 14 | import okhttp3.Request; 15 | import okhttp3.RequestBody; 16 | import okhttp3.Response; 17 | import okhttp3.ResponseBody; 18 | import okhttp3.internal.http.HttpHeaders; 19 | import okio.Buffer; 20 | import ricky.oknet.utils.JsonPrinter; 21 | import ricky.oknet.utils.OkLogger; 22 | 23 | public class HttpLoggingInterceptor implements Interceptor { 24 | 25 | private static final Charset UTF8 = Charset.forName("UTF-8"); 26 | 27 | private volatile Level printLevel = Level.NONE; 28 | private java.util.logging.Level colorLevel; 29 | private Logger logger; 30 | 31 | public enum Level { 32 | NONE, //不打印log 33 | BASIC, //只打印 请求首行 和 响应首行 34 | HEADERS, //打印请求和响应的所有 Header 35 | BODY //所有数据全部打印 36 | } 37 | 38 | public HttpLoggingInterceptor(String tag) { 39 | logger = Logger.getLogger(tag); 40 | JsonPrinter.TAG = tag; 41 | } 42 | 43 | public void setPrintLevel(Level level) { 44 | printLevel = level; 45 | } 46 | 47 | public void setColorLevel(java.util.logging.Level level) { 48 | colorLevel = level; 49 | } 50 | 51 | public void log(String message) { 52 | logger.log(colorLevel, message); 53 | } 54 | 55 | @Override 56 | public Response intercept(Chain chain) throws IOException { 57 | Request request = chain.request(); 58 | if (printLevel == Level.NONE) { 59 | return chain.proceed(request); 60 | } 61 | 62 | //请求日志拦截 63 | logForRequest(request, chain.connection()); 64 | 65 | //执行请求,计算请求时间 66 | long startNs = System.nanoTime(); 67 | Response response; 68 | try { 69 | response = chain.proceed(request); 70 | } catch (Exception e) { 71 | log("<-- HTTP FAILED: " + e); 72 | throw e; 73 | } 74 | long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); 75 | 76 | //响应日志拦截 77 | return logForResponse(response, tookMs); 78 | } 79 | 80 | private void logForRequest(Request request, Connection connection) throws IOException { 81 | boolean logBody = (printLevel == Level.BODY); 82 | boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS); 83 | RequestBody requestBody = request.body(); 84 | boolean hasRequestBody = requestBody != null; 85 | Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1; 86 | 87 | try { 88 | String requestStartMessage = "--> " + request.method() + ' ' + request.url() + ' ' + protocol; 89 | log(requestStartMessage); 90 | 91 | if (logHeaders) { 92 | Headers headers = request.headers(); 93 | for (int i = 0, count = headers.size(); i < count; i++) { 94 | log("\t" + headers.name(i) + ": " + headers.value(i)); 95 | } 96 | 97 | log(" "); 98 | if (logBody && hasRequestBody) { 99 | if (isPlaintext(requestBody.contentType())) { 100 | bodyToString(request); 101 | } else { 102 | log("\tbody: maybe [file part] , too large too print , ignored!"); 103 | } 104 | } 105 | } 106 | } catch (Exception e) { 107 | OkLogger.e(e); 108 | } finally { 109 | log("--> END " + request.method()); 110 | } 111 | } 112 | 113 | private Response logForResponse(Response response, long tookMs) { 114 | Response.Builder builder = response.newBuilder(); 115 | Response clone = builder.build(); 116 | ResponseBody responseBody = clone.body(); 117 | boolean logBody = (printLevel == Level.BODY); 118 | boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS); 119 | 120 | try { 121 | log("<-- " + clone.code() + ' ' + clone.message() + ' ' + clone.request().url() + " (" + tookMs + "ms)"); 122 | if (logHeaders) { 123 | Headers headers = clone.headers(); 124 | for (int i = 0, count = headers.size(); i < count; i++) { 125 | log("\t" + headers.name(i) + ": " + headers.value(i)); 126 | } 127 | log(" "); 128 | if (logBody && HttpHeaders.hasBody(clone)) { 129 | if (isPlaintext(responseBody.contentType())) { 130 | final String body = responseBody.string(); 131 | log("\tbody:" ); 132 | JsonPrinter.json(body, new Runnable() { 133 | @Override 134 | public void run() { 135 | log(body); 136 | } 137 | }); 138 | responseBody = ResponseBody.create(responseBody.contentType(), body); 139 | return response.newBuilder().body(responseBody).build(); 140 | } else { 141 | log("\tbody: maybe [file part] , too large too print , ignored!"); 142 | } 143 | } 144 | } 145 | } catch (Exception e) { 146 | OkLogger.e(e); 147 | } finally { 148 | log("<-- END HTTP"); 149 | } 150 | return response; 151 | } 152 | 153 | /** 154 | * Returns true if the body in question probably contains human readable text. Uses a small sample 155 | * of code points to detect unicode control characters commonly used in binary file signatures. 156 | */ 157 | private static boolean isPlaintext(MediaType mediaType) { 158 | if (mediaType == null) return false; 159 | if (mediaType.type() != null && mediaType.type().equals("text")) { 160 | return true; 161 | } 162 | String subtype = mediaType.subtype(); 163 | if (subtype != null) { 164 | subtype = subtype.toLowerCase(); 165 | if (subtype.contains("x-www-form-urlencoded") || 166 | subtype.contains("json") || 167 | subtype.contains("xml") || 168 | subtype.contains("html")) // 169 | return true; 170 | } 171 | return false; 172 | } 173 | 174 | private void bodyToString(Request request) { 175 | try { 176 | final Request copy = request.newBuilder().build(); 177 | final Buffer buffer = new Buffer(); 178 | copy.body().writeTo(buffer); 179 | Charset charset = UTF8; 180 | MediaType contentType = copy.body().contentType(); 181 | if (contentType != null) { 182 | charset = contentType.charset(UTF8); 183 | } 184 | final String s = buffer.readString(charset); 185 | log("\tbody:" ); 186 | JsonPrinter.json(s, new Runnable() { 187 | @Override 188 | public void run() { 189 | log(s); 190 | } 191 | }); 192 | } catch (Exception e) { 193 | e.printStackTrace(); 194 | } 195 | } 196 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/lifecycle/INet.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.lifecycle; 2 | 3 | import ricky.oknet.callback.AbsCallback; 4 | import ricky.oknet.convert.Converter; 5 | import rx.Observable; 6 | 7 | public interface INet { 8 | 9 | void execute(AbsCallback callback, INetQueue... iNetQueue); 10 | 11 | Observable rx(Converter converter, AbsCallback callback, INetQueue... iNetQueue); 12 | 13 | void cancel(); 14 | } 15 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/lifecycle/INetQueue.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.lifecycle; 2 | 3 | import ricky.oknet.retrofit.Net; 4 | import rx.Subscription; 5 | 6 | public interface INetQueue { 7 | 8 | //normal 9 | void add(Net net); 10 | 11 | //rx 12 | void addSubscription(Subscription subscription); 13 | 14 | void cancel(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/lifecycle/NetQueue.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.lifecycle; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | import ricky.oknet.retrofit.Net; 8 | import rx.Subscription; 9 | 10 | public class NetQueue implements INetQueue { 11 | 12 | private List> mQueue = new LinkedList<>(); 13 | private List mSubscriptionQueue = new LinkedList<>(); 14 | 15 | @Override 16 | public void add(Net net) { 17 | mQueue.add(net); 18 | } 19 | 20 | @Override 21 | public void addSubscription(Subscription subscription) { 22 | mSubscriptionQueue.add(subscription); 23 | } 24 | 25 | @Override 26 | public void cancel() { 27 | //normal mode 28 | ArrayList> queueCopy = new ArrayList<>(); 29 | queueCopy.addAll(this.mQueue); 30 | 31 | this.mQueue.clear(); 32 | for (Net mNet : queueCopy) { 33 | mNet.cancel(); 34 | } 35 | //rx mode 36 | ArrayList queueSubCopy = new ArrayList<>(); 37 | queueSubCopy.addAll(this.mSubscriptionQueue); 38 | 39 | 40 | this.mSubscriptionQueue.clear(); 41 | for (Subscription s : queueSubCopy) { 42 | if (!s.isUnsubscribed()) { 43 | s.unsubscribe(); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/model/HttpHeaders.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.model; 2 | 3 | import android.os.Build; 4 | import android.text.TextUtils; 5 | 6 | 7 | import org.json.JSONException; 8 | import org.json.JSONObject; 9 | 10 | import java.io.Serializable; 11 | import java.lang.reflect.Field; 12 | import java.text.ParseException; 13 | import java.text.SimpleDateFormat; 14 | import java.util.Date; 15 | import java.util.LinkedHashMap; 16 | import java.util.Locale; 17 | import java.util.Map; 18 | import java.util.Set; 19 | import java.util.TimeZone; 20 | 21 | import ricky.oknet.OkGo; 22 | import ricky.oknet.utils.OkLogger; 23 | 24 | public class HttpHeaders implements Serializable { 25 | 26 | private static final long serialVersionUID = 8458647755751403873L; 27 | 28 | public static final String FORMAT_HTTP_DATA = "EEE, dd MMM y HH:mm:ss 'GMT'"; 29 | public static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone("GMT"); 30 | 31 | public static final String HEAD_KEY_RESPONSE_CODE = "ResponseCode"; 32 | public static final String HEAD_KEY_RESPONSE_MESSAGE = "ResponseMessage"; 33 | public static final String HEAD_KEY_ACCEPT = "Accept"; 34 | public static final String HEAD_KEY_ACCEPT_ENCODING = "Accept-Encoding"; 35 | public static final String HEAD_VALUE_ACCEPT_ENCODING = "gzip, deflate"; 36 | public static final String HEAD_KEY_ACCEPT_LANGUAGE = "Accept-Language"; 37 | public static final String HEAD_KEY_CONTENT_TYPE = "Content-Type"; 38 | public static final String HEAD_KEY_CONTENT_LENGTH = "Content-Length"; 39 | public static final String HEAD_KEY_CONTENT_ENCODING = "Content-Encoding"; 40 | public static final String HEAD_KEY_CONTENT_DISPOSITION = "Content-Disposition"; 41 | public static final String HEAD_KEY_CONTENT_RANGE = "Content-Range"; 42 | public static final String HEAD_KEY_CACHE_CONTROL = "Cache-Control"; 43 | public static final String HEAD_KEY_CONNECTION = "Connection"; 44 | public static final String HEAD_VALUE_CONNECTION_KEEP_ALIVE = "keep-alive"; 45 | public static final String HEAD_VALUE_CONNECTION_CLOSE = "close"; 46 | public static final String HEAD_KEY_DATE = "Date"; 47 | public static final String HEAD_KEY_EXPIRES = "Expires"; 48 | public static final String HEAD_KEY_E_TAG = "ETag"; 49 | public static final String HEAD_KEY_PRAGMA = "Pragma"; 50 | public static final String HEAD_KEY_IF_MODIFIED_SINCE = "If-Modified-Since"; 51 | public static final String HEAD_KEY_IF_NONE_MATCH = "If-None-Match"; 52 | public static final String HEAD_KEY_LAST_MODIFIED = "Last-Modified"; 53 | public static final String HEAD_KEY_LOCATION = "Location"; 54 | public static final String HEAD_KEY_USER_AGENT = "User-Agent"; 55 | public static final String HEAD_KEY_COOKIE = "Cookie"; 56 | public static final String HEAD_KEY_COOKIE2 = "Cookie2"; 57 | public static final String HEAD_KEY_SET_COOKIE = "Set-Cookie"; 58 | public static final String HEAD_KEY_SET_COOKIE2 = "Set-Cookie2"; 59 | 60 | public LinkedHashMap headersMap; 61 | private static String acceptLanguage; 62 | private static String userAgent; 63 | 64 | private void init() { 65 | headersMap = new LinkedHashMap<>(); 66 | } 67 | 68 | public HttpHeaders() { 69 | init(); 70 | } 71 | 72 | public HttpHeaders(String key, String value) { 73 | init(); 74 | put(key, value); 75 | } 76 | 77 | public void put(String key, String value) { 78 | if (key != null && value != null) { 79 | headersMap.put(key, value); 80 | } 81 | } 82 | 83 | public void put(HttpHeaders headers) { 84 | if (headers != null) { 85 | if (headers.headersMap != null && !headers.headersMap.isEmpty()) headersMap.putAll(headers.headersMap); 86 | } 87 | } 88 | 89 | public String get(String key) { 90 | return headersMap.get(key); 91 | } 92 | 93 | public String remove(String key) { 94 | return headersMap.remove(key); 95 | } 96 | 97 | public void clear() { 98 | headersMap.clear(); 99 | } 100 | 101 | public Set getNames() { 102 | return headersMap.keySet(); 103 | } 104 | 105 | public final String toJSONString() { 106 | JSONObject jsonObject = new JSONObject(); 107 | try { 108 | for (Map.Entry entry : headersMap.entrySet()) { 109 | jsonObject.put(entry.getKey(), entry.getValue()); 110 | } 111 | } catch (JSONException e) { 112 | OkLogger.e(e); 113 | } 114 | return jsonObject.toString(); 115 | } 116 | 117 | public static long getDate(String gmtTime) { 118 | try { 119 | return parseGMTToMillis(gmtTime); 120 | } catch (ParseException e) { 121 | return 0; 122 | } 123 | } 124 | 125 | public static String getDate(long milliseconds) { 126 | return formatMillisToGMT(milliseconds); 127 | } 128 | 129 | public static long getExpiration(String expiresTime) { 130 | try { 131 | return parseGMTToMillis(expiresTime); 132 | } catch (ParseException e) { 133 | return -1; 134 | } 135 | } 136 | 137 | public static long getLastModified(String lastModified) { 138 | try { 139 | return parseGMTToMillis(lastModified); 140 | } catch (ParseException e) { 141 | return 0; 142 | } 143 | } 144 | 145 | public static String getCacheControl(String cacheControl, String pragma) { 146 | // first http1.1, second http1.0 147 | if (cacheControl != null) return cacheControl; 148 | else if (pragma != null) return pragma; 149 | else return null; 150 | } 151 | 152 | public static void setAcceptLanguage(String language) { 153 | acceptLanguage = language; 154 | } 155 | 156 | /** 157 | * Accept-Language: zh-CN,zh;q=0.8 158 | */ 159 | public static String getAcceptLanguage() { 160 | if (TextUtils.isEmpty(acceptLanguage)) { 161 | Locale locale = Locale.getDefault(); 162 | String language = locale.getLanguage(); 163 | String country = locale.getCountry(); 164 | StringBuilder acceptLanguageBuilder = new StringBuilder(language); 165 | if (!TextUtils.isEmpty(country)) acceptLanguageBuilder.append('-').append(country).append(',').append(language).append(";q=0.8"); 166 | acceptLanguage = acceptLanguageBuilder.toString(); 167 | return acceptLanguage; 168 | } 169 | return acceptLanguage; 170 | } 171 | 172 | public static void setUserAgent(String agent) { 173 | userAgent = agent; 174 | } 175 | 176 | /** 177 | * User-Agent: Mozilla/5.0 (Linux; U; Android 5.0.2; zh-cn; Redmi Note 3 Build/LRX22G) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 178 | */ 179 | public static String getUserAgent() { 180 | if (TextUtils.isEmpty(userAgent)) { 181 | String webUserAgent = null; 182 | try { 183 | Class sysResCls = Class.forName("com.android.internal.R$string"); 184 | Field webUserAgentField = sysResCls.getDeclaredField("web_user_agent"); 185 | Integer resId = (Integer) webUserAgentField.get(null); 186 | webUserAgent = OkGo.getContext().getString(resId); 187 | } catch (Exception e) { 188 | // We have nothing to do 189 | } 190 | if (TextUtils.isEmpty(webUserAgent)) { 191 | webUserAgent = "Mozilla/5.0 (Linux; U; Android %s) AppleWebKit/533.1 (KHTML, like Gecko) Version/5.0 %sSafari/533.1"; 192 | } 193 | 194 | Locale locale = Locale.getDefault(); 195 | StringBuffer buffer = new StringBuffer(); 196 | // Add version 197 | final String version = Build.VERSION.RELEASE; 198 | if (version.length() > 0) { 199 | buffer.append(version); 200 | } else { 201 | // default to "1.0" 202 | buffer.append("1.0"); 203 | } 204 | buffer.append("; "); 205 | final String language = locale.getLanguage(); 206 | if (language != null) { 207 | buffer.append(language.toLowerCase(locale)); 208 | final String country = locale.getCountry(); 209 | if (!TextUtils.isEmpty(country)) { 210 | buffer.append("-"); 211 | buffer.append(country.toLowerCase(locale)); 212 | } 213 | } else { 214 | // default to "en" 215 | buffer.append("en"); 216 | } 217 | // add the model for the release build 218 | if ("REL".equals(Build.VERSION.CODENAME)) { 219 | final String model = Build.MODEL; 220 | if (model.length() > 0) { 221 | buffer.append("; "); 222 | buffer.append(model); 223 | } 224 | } 225 | final String id = Build.ID; 226 | if (id.length() > 0) { 227 | buffer.append(" Build/"); 228 | buffer.append(id); 229 | } 230 | userAgent = String.format(webUserAgent, buffer, "Mobile "); 231 | return userAgent; 232 | } 233 | return userAgent; 234 | } 235 | 236 | public static long parseGMTToMillis(String gmtTime) throws ParseException { 237 | if (TextUtils.isEmpty(gmtTime)) return 0; 238 | SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_HTTP_DATA, Locale.US); 239 | formatter.setTimeZone(GMT_TIME_ZONE); 240 | Date date = formatter.parse(gmtTime); 241 | return date.getTime(); 242 | } 243 | 244 | public static String formatMillisToGMT(long milliseconds) { 245 | Date date = new Date(milliseconds); 246 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat(FORMAT_HTTP_DATA, Locale.US); 247 | simpleDateFormat.setTimeZone(GMT_TIME_ZONE); 248 | return simpleDateFormat.format(date); 249 | } 250 | 251 | @Override 252 | public String toString() { 253 | return "HttpHeaders{" + "headersMap=" + headersMap + '}'; 254 | } 255 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/model/HttpParams.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.model; 2 | 3 | import java.io.File; 4 | import java.io.Serializable; 5 | import java.net.FileNameMap; 6 | import java.net.URLConnection; 7 | import java.util.ArrayList; 8 | import java.util.LinkedHashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | import okhttp3.MediaType; 14 | 15 | public class HttpParams implements Serializable { 16 | 17 | private static final long serialVersionUID = 7369819159227055048L; 18 | 19 | public static final MediaType MEDIA_TYPE_PLAIN = MediaType.parse("text/plain;charset=utf-8"); 20 | public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json;charset=utf-8"); 21 | public static final MediaType MEDIA_TYPE_STREAM = MediaType.parse("application/octet-stream"); 22 | 23 | public static final boolean IS_REPLACE = true; 24 | 25 | /** 普通的键值对参数 */ 26 | public LinkedHashMap> urlParamsMap; 27 | 28 | /** 文件的键值对参数 */ 29 | public LinkedHashMap> fileParamsMap; 30 | 31 | public HttpParams() { 32 | init(); 33 | } 34 | 35 | public HttpParams(String key, String value) { 36 | init(); 37 | put(key, value, IS_REPLACE); 38 | } 39 | 40 | public HttpParams(String key, File file) { 41 | init(); 42 | put(key, file); 43 | } 44 | 45 | private void init() { 46 | urlParamsMap = new LinkedHashMap<>(); 47 | fileParamsMap = new LinkedHashMap<>(); 48 | } 49 | 50 | public void put(HttpParams params) { 51 | if (params != null) { 52 | if (params.urlParamsMap != null && !params.urlParamsMap.isEmpty()) urlParamsMap.putAll(params.urlParamsMap); 53 | if (params.fileParamsMap != null && !params.fileParamsMap.isEmpty()) fileParamsMap.putAll(params.fileParamsMap); 54 | } 55 | } 56 | 57 | public void put(Map params, boolean... isReplace) { 58 | if (params == null || params.isEmpty()) return; 59 | for (Map.Entry entry : params.entrySet()) { 60 | put(entry.getKey(), entry.getValue(), isReplace); 61 | } 62 | } 63 | 64 | public void put(String key, String value, boolean... isReplace) { 65 | if (isReplace != null && isReplace.length > 0) { 66 | put(key, value, isReplace[0]); 67 | } else { 68 | put(key, value, IS_REPLACE); 69 | } 70 | } 71 | 72 | public void put(String key, int value, boolean... isReplace) { 73 | if (isReplace != null && isReplace.length > 0) { 74 | put(key, String.valueOf(value), isReplace[0]); 75 | } else { 76 | put(key, String.valueOf(value), IS_REPLACE); 77 | } 78 | } 79 | 80 | public void put(String key, long value, boolean... isReplace) { 81 | if (isReplace != null && isReplace.length > 0) { 82 | put(key, String.valueOf(value), isReplace[0]); 83 | } else { 84 | put(key, String.valueOf(value), IS_REPLACE); 85 | } 86 | } 87 | 88 | public void put(String key, float value, boolean... isReplace) { 89 | if (isReplace != null && isReplace.length > 0) { 90 | put(key, String.valueOf(value), isReplace[0]); 91 | } else { 92 | put(key, String.valueOf(value), IS_REPLACE); 93 | } 94 | } 95 | 96 | public void put(String key, double value, boolean... isReplace) { 97 | if (isReplace != null && isReplace.length > 0) { 98 | put(key, String.valueOf(value), isReplace[0]); 99 | } else { 100 | put(key, String.valueOf(value), IS_REPLACE); 101 | } 102 | } 103 | 104 | public void put(String key, char value, boolean... isReplace) { 105 | if (isReplace != null && isReplace.length > 0) { 106 | put(key, String.valueOf(value), isReplace[0]); 107 | } else { 108 | put(key, String.valueOf(value), IS_REPLACE); 109 | } 110 | } 111 | 112 | public void put(String key, boolean value, boolean... isReplace) { 113 | if (isReplace != null && isReplace.length > 0) { 114 | put(key, String.valueOf(value), isReplace[0]); 115 | } else { 116 | put(key, String.valueOf(value), IS_REPLACE); 117 | } 118 | } 119 | 120 | private void put(String key, String value, boolean isReplace) { 121 | if (key != null && value != null) { 122 | List urlValues = urlParamsMap.get(key); 123 | if (urlValues == null) { 124 | urlValues = new ArrayList<>(); 125 | urlParamsMap.put(key, urlValues); 126 | } 127 | if (isReplace) urlValues.clear(); 128 | urlValues.add(value); 129 | } 130 | } 131 | 132 | public void putUrlParams(String key, List values) { 133 | if (key != null && values != null && !values.isEmpty()) { 134 | for (String value : values) { 135 | put(key, value, false); 136 | } 137 | } 138 | } 139 | 140 | public void put(String key, File file) { 141 | put(key, file, file.getName()); 142 | } 143 | 144 | public void put(String key, File file, String fileName) { 145 | put(key, file, fileName, guessMimeType(fileName)); 146 | } 147 | 148 | public void put(String key, FileWrapper fileWrapper) { 149 | if (key != null && fileWrapper != null) { 150 | put(key, fileWrapper.file, fileWrapper.fileName, fileWrapper.contentType); 151 | } 152 | } 153 | 154 | public void put(String key, File file, String fileName, MediaType contentType) { 155 | if (key != null) { 156 | List fileWrappers = fileParamsMap.get(key); 157 | if (fileWrappers == null) { 158 | fileWrappers = new ArrayList<>(); 159 | fileParamsMap.put(key, fileWrappers); 160 | } 161 | fileWrappers.add(new FileWrapper(file, fileName, contentType)); 162 | } 163 | } 164 | 165 | public void putFileParams(String key, List files) { 166 | if (key != null && files != null && !files.isEmpty()) { 167 | for (File file : files) { 168 | put(key, file); 169 | } 170 | } 171 | } 172 | 173 | public void putFileWrapperParams(String key, List fileWrappers) { 174 | if (key != null && fileWrappers != null && !fileWrappers.isEmpty()) { 175 | for (FileWrapper fileWrapper : fileWrappers) { 176 | put(key, fileWrapper); 177 | } 178 | } 179 | } 180 | 181 | public void removeUrl(String key) { 182 | urlParamsMap.remove(key); 183 | } 184 | 185 | public void removeFile(String key) { 186 | fileParamsMap.remove(key); 187 | } 188 | 189 | public void remove(String key) { 190 | removeUrl(key); 191 | removeFile(key); 192 | } 193 | 194 | public void clear() { 195 | urlParamsMap.clear(); 196 | fileParamsMap.clear(); 197 | } 198 | 199 | private MediaType guessMimeType(String path) { 200 | FileNameMap fileNameMap = URLConnection.getFileNameMap(); 201 | path = path.replace("#", ""); //解决文件名中含有#号异常的问题 202 | String contentType = fileNameMap.getContentTypeFor(path); 203 | if (contentType == null) { 204 | contentType = "application/octet-stream"; 205 | } 206 | return MediaType.parse(contentType); 207 | } 208 | 209 | /** 文件类型的包装类 */ 210 | public static class FileWrapper { 211 | public File file; 212 | public String fileName; 213 | public MediaType contentType; 214 | public long fileSize; 215 | 216 | public FileWrapper(File file, String fileName, MediaType contentType) { 217 | this.file = file; 218 | this.fileName = fileName; 219 | this.contentType = contentType; 220 | this.fileSize = file.length(); 221 | } 222 | 223 | @Override 224 | public String toString() { 225 | return "FileWrapper{" + "file=" + file + ", fileName='" + fileName + ", contentType=" + contentType + ", fileSize=" + fileSize + '}'; 226 | } 227 | } 228 | 229 | @Override 230 | public String toString() { 231 | StringBuilder result = new StringBuilder(); 232 | for (ConcurrentHashMap.Entry> entry : urlParamsMap.entrySet()) { 233 | if (result.length() > 0) result.append("&"); 234 | result.append(entry.getKey()).append("=").append(entry.getValue()); 235 | } 236 | for (ConcurrentHashMap.Entry> entry : fileParamsMap.entrySet()) { 237 | if (result.length() > 0) result.append("&"); 238 | result.append(entry.getKey()).append("=").append(entry.getValue()); 239 | } 240 | return result.toString(); 241 | } 242 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/model/Response.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.model; 2 | 3 | import okhttp3.Headers; 4 | 5 | public final class Response { 6 | 7 | private final okhttp3.Response rawResponse; 8 | private final T body; 9 | 10 | private Response(okhttp3.Response rawResponse, T body) { 11 | this.rawResponse = rawResponse; 12 | this.body = body; 13 | } 14 | 15 | public okhttp3.Response raw() { 16 | return rawResponse; 17 | } 18 | 19 | public int code() { 20 | return rawResponse.code(); 21 | } 22 | 23 | public String message() { 24 | return rawResponse.message(); 25 | } 26 | 27 | public Headers headers() { 28 | return rawResponse.headers(); 29 | } 30 | 31 | public boolean isSuccessful() { 32 | return rawResponse.isSuccessful(); 33 | } 34 | 35 | public T body() { 36 | return body; 37 | } 38 | 39 | public static Response success(T body, okhttp3.Response rawResponse) { 40 | if (rawResponse == null) throw new NullPointerException("rawResponse == null"); 41 | if (!rawResponse.isSuccessful()) throw new IllegalArgumentException("rawResponse must be successful response"); 42 | return new Response<>(rawResponse, body); 43 | } 44 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/request/BaseBodyRequest.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.request; 2 | 3 | 4 | import org.json.JSONArray; 5 | import org.json.JSONObject; 6 | 7 | import java.io.File; 8 | import java.util.List; 9 | 10 | import okhttp3.MediaType; 11 | import okhttp3.RequestBody; 12 | import ricky.oknet.model.HttpParams; 13 | import ricky.oknet.utils.HttpUtils; 14 | 15 | public abstract class BaseBodyRequest extends BaseRequest implements HasBody { 16 | 17 | protected MediaType mediaType; //上传的MIME类型 18 | protected String content; //上传的文本内容 19 | protected byte[] bs; //上传的字节数据 20 | 21 | protected boolean isMultipart = false; //是否强制使用 multipart/form-data 表单上传 22 | protected RequestBody requestBody; 23 | 24 | public BaseBodyRequest(String url) { 25 | super(url); 26 | } 27 | 28 | @SuppressWarnings("unchecked") 29 | @Override 30 | public R isMultipart(boolean isMultipart) { 31 | this.isMultipart = isMultipart; 32 | return (R) this; 33 | } 34 | 35 | @SuppressWarnings("unchecked") 36 | @Override 37 | public R requestBody(RequestBody requestBody) { 38 | this.requestBody = requestBody; 39 | return (R) this; 40 | } 41 | 42 | @SuppressWarnings("unchecked") 43 | @Override 44 | public R params(String key, File file) { 45 | params.put(key, file); 46 | return (R) this; 47 | } 48 | 49 | @SuppressWarnings("unchecked") 50 | @Override 51 | public R addFileParams(String key, List files) { 52 | params.putFileParams(key, files); 53 | return (R) this; 54 | } 55 | 56 | @SuppressWarnings("unchecked") 57 | @Override 58 | public R addFileWrapperParams(String key, List fileWrappers) { 59 | params.putFileWrapperParams(key, fileWrappers); 60 | return (R) this; 61 | } 62 | 63 | @SuppressWarnings("unchecked") 64 | @Override 65 | public R params(String key, File file, String fileName) { 66 | params.put(key, file, fileName); 67 | return (R) this; 68 | } 69 | 70 | @SuppressWarnings("unchecked") 71 | @Override 72 | public R params(String key, File file, String fileName, MediaType contentType) { 73 | params.put(key, file, fileName, contentType); 74 | return (R) this; 75 | } 76 | 77 | /** 注意使用该方法上传字符串会清空实体中其他所有的参数,头信息不清除 */ 78 | @SuppressWarnings("unchecked") 79 | @Override 80 | public R upString(String string) { 81 | this.content = string; 82 | this.mediaType = HttpParams.MEDIA_TYPE_PLAIN; 83 | return (R) this; 84 | } 85 | 86 | /** 87 | * 注意使用该方法上传字符串会清空实体中其他所有的参数,头信息不清除 88 | * 该方法用于定制请求content-type 89 | */ 90 | @SuppressWarnings("unchecked") 91 | public R upString(String string, MediaType mediaType) { 92 | this.content = string; 93 | this.mediaType = mediaType; 94 | return (R) this; 95 | } 96 | 97 | /** 注意使用该方法上传字符串会清空实体中其他所有的参数,头信息不清除 */ 98 | @SuppressWarnings("unchecked") 99 | @Override 100 | public R upJson(String json) { 101 | this.content = json; 102 | this.mediaType = HttpParams.MEDIA_TYPE_JSON; 103 | return (R) this; 104 | } 105 | 106 | /** 注意使用该方法上传字符串会清空实体中其他所有的参数,头信息不清除 */ 107 | @SuppressWarnings("unchecked") 108 | @Override 109 | public R upJson(JSONObject jsonObject) { 110 | this.content = jsonObject.toString(); 111 | this.mediaType = HttpParams.MEDIA_TYPE_JSON; 112 | return (R) this; 113 | } 114 | 115 | /** 注意使用该方法上传字符串会清空实体中其他所有的参数,头信息不清除 */ 116 | @SuppressWarnings("unchecked") 117 | @Override 118 | public R upJson(JSONArray jsonArray) { 119 | this.content = jsonArray.toString(); 120 | this.mediaType = HttpParams.MEDIA_TYPE_JSON; 121 | return (R) this; 122 | } 123 | 124 | /** 注意使用该方法上传字符串会清空实体中其他所有的参数,头信息不清除 */ 125 | @SuppressWarnings("unchecked") 126 | @Override 127 | public R upBytes(byte[] bs) { 128 | this.bs = bs; 129 | this.mediaType = HttpParams.MEDIA_TYPE_STREAM; 130 | return (R) this; 131 | } 132 | 133 | @Override 134 | public RequestBody generateRequestBody() { 135 | if (requestBody != null) return requestBody; //自定义的请求体 136 | if (content != null && mediaType != null) return RequestBody.create(mediaType, content); //post上传字符串数据 137 | if (bs != null && mediaType != null) return RequestBody.create(mediaType, bs); //post上传字节数组 138 | return HttpUtils.generateMultipartRequestBody(params, isMultipart); 139 | } 140 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/request/DeleteRequest.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.request; 2 | 3 | 4 | import java.io.IOException; 5 | 6 | import okhttp3.Request; 7 | import okhttp3.RequestBody; 8 | import ricky.oknet.model.HttpHeaders; 9 | import ricky.oknet.utils.HttpUtils; 10 | import ricky.oknet.utils.OkLogger; 11 | 12 | public class DeleteRequest extends BaseBodyRequest { 13 | 14 | public DeleteRequest(String url) { 15 | super(url); 16 | method = "DELETE"; 17 | } 18 | 19 | @Override 20 | public Request generateRequest(RequestBody requestBody) { 21 | try { 22 | headers.put(HttpHeaders.HEAD_KEY_CONTENT_LENGTH, String.valueOf(requestBody.contentLength())); 23 | } catch (IOException e) { 24 | OkLogger.e(e); 25 | } 26 | Request.Builder requestBuilder = HttpUtils.appendHeaders(headers); 27 | return requestBuilder.delete(requestBody).url(url).tag(tag).build(); 28 | } 29 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/request/GetRequest.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.request; 2 | 3 | 4 | import okhttp3.Request; 5 | import okhttp3.RequestBody; 6 | import ricky.oknet.utils.HttpUtils; 7 | 8 | public class GetRequest extends BaseRequest { 9 | 10 | public GetRequest(String url) { 11 | super(url); 12 | method = "GET"; 13 | } 14 | 15 | @Override 16 | public RequestBody generateRequestBody() { 17 | return null; 18 | } 19 | 20 | @Override 21 | public Request generateRequest(RequestBody requestBody) { 22 | Request.Builder requestBuilder = HttpUtils.appendHeaders(headers); 23 | url = HttpUtils.createUrlFromParams(baseUrl, params.urlParamsMap); 24 | return requestBuilder.get().url(url).tag(tag).build(); 25 | } 26 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/request/HasBody.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.request; 2 | 3 | 4 | import org.json.JSONArray; 5 | import org.json.JSONObject; 6 | 7 | import java.io.File; 8 | import java.util.List; 9 | 10 | import okhttp3.MediaType; 11 | import okhttp3.RequestBody; 12 | import ricky.oknet.model.HttpParams; 13 | 14 | public interface HasBody { 15 | 16 | R isMultipart(boolean isMultipart); 17 | 18 | R requestBody(RequestBody requestBody); 19 | 20 | R params(String key, File file); 21 | 22 | R addFileParams(String key, List files); 23 | 24 | R addFileWrapperParams(String key, List fileWrappers); 25 | 26 | R params(String key, File file, String fileName); 27 | 28 | R params(String key, File file, String fileName, MediaType contentType); 29 | 30 | R upString(String string); 31 | 32 | R upJson(String json); 33 | 34 | R upJson(JSONObject jsonObject); 35 | 36 | R upJson(JSONArray jsonArray); 37 | 38 | R upBytes(byte[] bs); 39 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/request/HeadRequest.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.request; 2 | 3 | 4 | import okhttp3.Request; 5 | import okhttp3.RequestBody; 6 | import ricky.oknet.utils.HttpUtils; 7 | 8 | public class HeadRequest extends BaseRequest { 9 | 10 | public HeadRequest(String url) { 11 | super(url); 12 | method = "HEAD"; 13 | } 14 | 15 | @Override 16 | public RequestBody generateRequestBody() { 17 | return null; 18 | } 19 | 20 | @Override 21 | public Request generateRequest(RequestBody requestBody) { 22 | Request.Builder requestBuilder = HttpUtils.appendHeaders(headers); 23 | url = HttpUtils.createUrlFromParams(baseUrl, params.urlParamsMap); 24 | return requestBuilder.head().url(url).tag(tag).build(); 25 | } 26 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/request/OptionsRequest.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.request; 2 | 3 | 4 | import java.io.IOException; 5 | 6 | import okhttp3.Request; 7 | import okhttp3.RequestBody; 8 | import ricky.oknet.model.HttpHeaders; 9 | import ricky.oknet.utils.HttpUtils; 10 | import ricky.oknet.utils.OkLogger; 11 | 12 | public class OptionsRequest extends BaseBodyRequest { 13 | 14 | public OptionsRequest(String url) { 15 | super(url); 16 | method = "OPTIONS"; 17 | } 18 | 19 | @Override 20 | public Request generateRequest(RequestBody requestBody) { 21 | try { 22 | headers.put(HttpHeaders.HEAD_KEY_CONTENT_LENGTH, String.valueOf(requestBody.contentLength())); 23 | } catch (IOException e) { 24 | OkLogger.e(e); 25 | } 26 | Request.Builder requestBuilder = HttpUtils.appendHeaders(headers); 27 | return requestBuilder.method("OPTIONS", requestBody).url(url).tag(tag).build(); 28 | } 29 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/request/PostRequest.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.request; 2 | 3 | 4 | import java.io.IOException; 5 | 6 | import okhttp3.Request; 7 | import okhttp3.RequestBody; 8 | import ricky.oknet.model.HttpHeaders; 9 | import ricky.oknet.utils.HttpUtils; 10 | import ricky.oknet.utils.OkLogger; 11 | 12 | public class PostRequest extends BaseBodyRequest { 13 | 14 | public PostRequest(String url) { 15 | super(url); 16 | method = "POST"; 17 | } 18 | 19 | @Override 20 | public Request generateRequest(RequestBody requestBody) { 21 | try { 22 | headers.put(HttpHeaders.HEAD_KEY_CONTENT_LENGTH, String.valueOf(requestBody.contentLength())); 23 | } catch (IOException e) { 24 | OkLogger.e(e); 25 | } 26 | Request.Builder requestBuilder = HttpUtils.appendHeaders(headers); 27 | return requestBuilder.post(requestBody).url(url).tag(tag).build(); 28 | } 29 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/request/ProgressRequestBody.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.request; 2 | 3 | 4 | import java.io.IOException; 5 | 6 | import okhttp3.MediaType; 7 | import okhttp3.RequestBody; 8 | import okio.Buffer; 9 | import okio.BufferedSink; 10 | import okio.ForwardingSink; 11 | import okio.Okio; 12 | import okio.Sink; 13 | import ricky.oknet.OkGo; 14 | import ricky.oknet.utils.OkLogger; 15 | 16 | /** 17 | * 包装的请求体,处理进度,可以处理任何的 RequestBody, 18 | * 但是一般用在 multipart requests 上传大文件的时候 19 | */ 20 | public class ProgressRequestBody extends RequestBody { 21 | 22 | protected RequestBody delegate; //实际的待包装请求体 23 | protected Listener listener; //进度回调接口 24 | protected CountingSink countingSink; //包装完成的BufferedSink 25 | 26 | public ProgressRequestBody(RequestBody delegate) { 27 | this.delegate = delegate; 28 | } 29 | 30 | public ProgressRequestBody(RequestBody delegate, Listener listener) { 31 | this.delegate = delegate; 32 | this.listener = listener; 33 | } 34 | 35 | public void setListener(Listener listener) { 36 | this.listener = listener; 37 | } 38 | 39 | /** 重写调用实际的响应体的contentType */ 40 | @Override 41 | public MediaType contentType() { 42 | return delegate.contentType(); 43 | } 44 | 45 | /** 重写调用实际的响应体的contentLength */ 46 | @Override 47 | public long contentLength() { 48 | try { 49 | return delegate.contentLength(); 50 | } catch (IOException e) { 51 | OkLogger.e(e); 52 | return -1; 53 | } 54 | } 55 | 56 | /** 重写进行写入 */ 57 | @Override 58 | public void writeTo(BufferedSink sink) throws IOException { 59 | countingSink = new CountingSink(sink); 60 | BufferedSink bufferedSink = Okio.buffer(countingSink); 61 | delegate.writeTo(bufferedSink); 62 | bufferedSink.flush(); //必须调用flush,否则最后一部分数据可能不会被写入 63 | } 64 | 65 | /** 包装 */ 66 | protected final class CountingSink extends ForwardingSink { 67 | private long bytesWritten = 0; //当前写入字节数 68 | private long contentLength = 0; //总字节长度,避免多次调用contentLength()方法 69 | private long lastRefreshUiTime; //最后一次刷新的时间 70 | private long lastWriteBytes; //最后一次写入字节数据 71 | 72 | public CountingSink(Sink delegate) { 73 | super(delegate); 74 | } 75 | 76 | @Override 77 | public void write(Buffer source, long byteCount) throws IOException { 78 | super.write(source, byteCount); 79 | if (contentLength <= 0) contentLength = contentLength(); //获得contentLength的值,后续不再调用 80 | bytesWritten += byteCount; 81 | 82 | long curTime = System.currentTimeMillis(); 83 | //每100毫秒刷新一次数据 84 | if (curTime - lastRefreshUiTime >= OkGo.REFRESH_TIME || bytesWritten == contentLength) { 85 | //计算下载速度 86 | long diffTime = (curTime - lastRefreshUiTime) / 1000; 87 | if (diffTime == 0) diffTime += 1; 88 | long diffBytes = bytesWritten - lastWriteBytes; 89 | long networkSpeed = diffBytes / diffTime; 90 | if (listener != null) listener.onRequestProgress(bytesWritten, contentLength, networkSpeed); 91 | 92 | lastRefreshUiTime = System.currentTimeMillis(); 93 | lastWriteBytes = bytesWritten; 94 | } 95 | } 96 | } 97 | 98 | /** 回调接口 */ 99 | public interface Listener { 100 | void onRequestProgress(long bytesWritten, long contentLength, long networkSpeed); 101 | } 102 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/request/PutRequest.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.request; 2 | 3 | 4 | import java.io.IOException; 5 | 6 | import okhttp3.Request; 7 | import okhttp3.RequestBody; 8 | import ricky.oknet.model.HttpHeaders; 9 | import ricky.oknet.utils.HttpUtils; 10 | import ricky.oknet.utils.OkLogger; 11 | 12 | public class PutRequest extends BaseBodyRequest { 13 | 14 | public PutRequest(String url) { 15 | super(url); 16 | method = "PUT"; 17 | } 18 | 19 | @Override 20 | public Request generateRequest(RequestBody requestBody) { 21 | try { 22 | headers.put(HttpHeaders.HEAD_KEY_CONTENT_LENGTH, String.valueOf(requestBody.contentLength())); 23 | } catch (IOException e) { 24 | OkLogger.e(e); 25 | } 26 | Request.Builder requestBuilder = HttpUtils.appendHeaders(headers); 27 | return requestBuilder.put(requestBody).url(url).tag(tag).build(); 28 | } 29 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/Net.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.retrofit; 2 | 3 | 4 | import ricky.oknet.OkGo; 5 | import ricky.oknet.callback.AbsCallback; 6 | import ricky.oknet.convert.Converter; 7 | import ricky.oknet.lifecycle.INet; 8 | import ricky.oknet.lifecycle.INetQueue; 9 | import ricky.oknet.request.BaseRequest; 10 | import ricky.oknet.request.DeleteRequest; 11 | import ricky.oknet.request.GetRequest; 12 | import ricky.oknet.request.HeadRequest; 13 | import ricky.oknet.request.OptionsRequest; 14 | import ricky.oknet.request.PostRequest; 15 | import ricky.oknet.request.PutRequest; 16 | import ricky.oknet.rx.RxAdapter; 17 | import rx.Observable; 18 | import rx.Subscription; 19 | import rx.android.schedulers.AndroidSchedulers; 20 | import rx.functions.Action0; 21 | import rx.functions.Action1; 22 | 23 | public class Net implements INet { 24 | 25 | private NetRequestData data; 26 | 27 | 28 | Net(NetRequestData data) { 29 | this.data = data; 30 | } 31 | 32 | /** 33 | * 执行请求 34 | * 35 | * @param callback 回调 36 | * @param iNetQueue 网络队列,用于管理网络与View的绑定 37 | */ 38 | @Override 39 | public void execute(AbsCallback callback, INetQueue... iNetQueue) { 40 | 41 | if (callback == null) { 42 | throw new IllegalArgumentException("callback not be null"); 43 | } 44 | 45 | BaseRequest req; 46 | switch (data.type) { 47 | case GET: 48 | req = OkGo.get(data.url); 49 | break; 50 | case POST: 51 | req = OkGo.post(data.url); 52 | break; 53 | case DELETE: 54 | req = OkGo.delete(data.url); 55 | break; 56 | case HEAD: 57 | req = OkGo.head(data.url); 58 | break; 59 | case OPTIONS: 60 | req = OkGo.options(data.url); 61 | break; 62 | case PUT: 63 | req = OkGo.put(data.url); 64 | break; 65 | case JSON: 66 | PostRequest rJson = OkGo.post(data.url); 67 | rJson.upJson(data.jsonParam); 68 | req = rJson; 69 | break; 70 | case BYTES: 71 | PostRequest rBytes = OkGo.post(data.url); 72 | rBytes.upBytes(data.byteParam); 73 | req = rBytes; 74 | break; 75 | case STRING: 76 | PostRequest rString = OkGo.post(data.url); 77 | rString.upString(data.stringParam); 78 | req = rString; 79 | break; 80 | default: 81 | throw new IllegalArgumentException("no match request type"); 82 | } 83 | 84 | if (data.cacheMode != null) { 85 | req.cacheMode(data.cacheMode); 86 | req.cacheTime(data.cacheTime); 87 | } 88 | if (data.header != null) { 89 | req.headers(data.header.key, data.header.value); 90 | } 91 | req.params(data.params); 92 | req.tag(data.methodName); 93 | 94 | //Take queue to take over 95 | if (iNetQueue != null && iNetQueue.length == 1) { 96 | INetQueue mINetQueue = iNetQueue[0]; 97 | mINetQueue.add(this); 98 | } 99 | 100 | req.execute(callback); 101 | 102 | } 103 | 104 | /** 105 | * 执行请求 106 | * 107 | * @param converter 数据转换 108 | * @param callback 传入则使用AbsCallback的回调与错误解析,简化配置默认Rx回调,不影响外部使用 109 | * @param iNetQueue 队列 110 | * @return 111 | */ 112 | @Override 113 | public Observable rx(Converter converter, final AbsCallback callback, INetQueue... iNetQueue) { 114 | 115 | final BaseRequest req; 116 | Observable ob; 117 | 118 | switch (data.type) { 119 | case GET: 120 | GetRequest g = OkGo.get(data.url); 121 | ob = g.getCall(converter, RxAdapter.create());//g must a request impl 122 | req = g; 123 | break; 124 | case POST: 125 | PostRequest p = OkGo.post(data.url); 126 | ob = p.getCall(converter, RxAdapter.create()); 127 | req = p; 128 | break; 129 | case DELETE: 130 | DeleteRequest d = OkGo.delete(data.url); 131 | ob = d.getCall(converter, RxAdapter.create()); 132 | req = d; 133 | break; 134 | case HEAD: 135 | HeadRequest h = OkGo.head(data.url); 136 | ob = h.getCall(converter, RxAdapter.create()); 137 | req = h; 138 | break; 139 | case OPTIONS: 140 | OptionsRequest o = OkGo.options(data.url); 141 | ob = o.getCall(converter, RxAdapter.create()); 142 | req = o; 143 | break; 144 | case PUT: 145 | PutRequest pu = OkGo.put(data.url); 146 | ob = pu.getCall(converter, RxAdapter.create()); 147 | req = pu; 148 | break; 149 | case JSON: 150 | PostRequest rJson = OkGo.post(data.url); 151 | rJson.upJson(data.jsonParam); 152 | ob = rJson.getCall(converter, RxAdapter.create()); 153 | req = rJson; 154 | break; 155 | case BYTES: 156 | PostRequest rBytes = OkGo.post(data.url); 157 | rBytes.upBytes(data.byteParam); 158 | ob = rBytes.getCall(converter, RxAdapter.create()); 159 | req = rBytes; 160 | break; 161 | case STRING: 162 | PostRequest rString = OkGo.post(data.url); 163 | rString.upString(data.stringParam); 164 | ob = rString.getCall(converter, RxAdapter.create()); 165 | req = rString; 166 | break; 167 | default: 168 | throw new IllegalArgumentException("no match request type"); 169 | } 170 | 171 | if (data.cacheMode != null) { 172 | req.cacheMode(data.cacheMode); 173 | req.cacheTime(data.cacheTime); 174 | } 175 | if (data.header != null) { 176 | req.headers(data.header.key, data.header.value); 177 | } 178 | req.params(data.params); 179 | 180 | 181 | if (callback != null) { 182 | //default config 183 | Subscription subscribe = ob.doOnSubscribe(new Action0() { 184 | @Override 185 | public void call() { 186 | callback.onBefore(req); 187 | } 188 | }) 189 | .observeOn(AndroidSchedulers.mainThread())//consumer thread 190 | .subscribe(new Action1() { 191 | @Override 192 | public void call(T t) { 193 | callback.onSuccess(t, null, null); 194 | } 195 | }, new Action1() { 196 | @Override 197 | public void call(Throwable throwable) { 198 | callback.onError(null, null, throwable); 199 | } 200 | }); 201 | //Take queue to take over 202 | if (iNetQueue != null && iNetQueue.length == 1) { 203 | INetQueue mINetQueue = iNetQueue[0]; 204 | mINetQueue.addSubscription(subscribe); 205 | } 206 | } 207 | 208 | return ob; 209 | 210 | } 211 | 212 | @Override 213 | public void cancel() { 214 | OkGo.getInstance().cancelTag(data.methodName); 215 | } 216 | 217 | } 218 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/NetRequestData.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.retrofit; 2 | 3 | import java.lang.reflect.Type; 4 | 5 | import ricky.oknet.cache.CacheMode; 6 | import ricky.oknet.model.HttpParams; 7 | 8 | class NetRequestData { 9 | 10 | HttpRequestContent requestContent; 11 | Type[] types; 12 | String methodName;//use tag 13 | String url; 14 | HttpRequestType type; 15 | 16 | //互斥 17 | HttpParams params; 18 | 19 | String jsonParam; 20 | byte[] byteParam; 21 | String stringParam; 22 | 23 | CacheMode cacheMode; 24 | long cacheTime; 25 | Header header; 26 | 27 | static class Header { 28 | public String key; 29 | public String value; 30 | } 31 | 32 | enum HttpRequestType { 33 | GET, POST, JSON, BYTES, STRING, DELETE, HEAD, OPTIONS, PUT 34 | } 35 | 36 | enum HttpRequestContent { 37 | DEFAULT, FILE 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/BYTES.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | public @interface BYTES { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/BytesParam.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RUNTIME) 15 | 16 | public @interface BytesParam { 17 | String value() default "bytes"; 18 | } 19 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/CACHE.java: -------------------------------------------------------------------------------- 1 | 2 | package ricky.oknet.retrofit.anno; 3 | 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.Target; 7 | 8 | import ricky.oknet.cache.CacheMode; 9 | 10 | import static java.lang.annotation.ElementType.METHOD; 11 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 12 | 13 | @Documented 14 | @Target(METHOD) 15 | @Retention(RUNTIME) 16 | public @interface CACHE { 17 | CacheMode value() default CacheMode.DEFAULT; 18 | } 19 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/CacheTime.java: -------------------------------------------------------------------------------- 1 | 2 | package ricky.oknet.retrofit.anno; 3 | 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.Target; 7 | 8 | import ricky.oknet.cache.CacheEntity; 9 | 10 | import static java.lang.annotation.ElementType.METHOD; 11 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 12 | 13 | @Documented 14 | @Target(METHOD) 15 | @Retention(RUNTIME) 16 | public @interface CacheTime { 17 | long value() default CacheEntity.CACHE_NEVER_EXPIRE; 18 | } 19 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/DELETE.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | public @interface DELETE { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/GET.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | public @interface GET { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/HEAD.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | public @interface HEAD { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/HEADER.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | /** 16 | * 需要设置更多header,可在callBack的onBefore中得到BaseRequest设置 17 | */ 18 | public @interface HEADER { 19 | 20 | String key() default ""; 21 | 22 | String value() default ""; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/JSON.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | public @interface JSON { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/JsonParam.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RUNTIME) 15 | 16 | public @interface JsonParam { 17 | String value() default "json"; 18 | } 19 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/OPTIONS.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | public @interface OPTIONS { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/POST.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | public @interface POST { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/PUT.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | public @interface PUT { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/Param.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RUNTIME) 15 | /** 16 | * 非json、string、bytes模式下,标记方法参数 17 | */ 18 | public @interface Param { 19 | String value() default ""; 20 | } 21 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/Path.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RUNTIME) 15 | /** 16 | * 用于替换url中占位符 17 | */ 18 | public @interface Path { 19 | String value() default ""; 20 | } 21 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/STRING.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(METHOD) 14 | @Retention(RUNTIME) 15 | public @interface STRING { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/retrofit/anno/StringParam.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package ricky.oknet.retrofit.anno; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.Target; 9 | 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | @Documented 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RUNTIME) 15 | 16 | public @interface StringParam { 17 | String value() default "string"; 18 | } 19 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/rx/HttpException.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.rx; 2 | 3 | import ricky.oknet.model.Response; 4 | 5 | /** Exception for an unexpected, non-2xx HTTP response. */ 6 | public final class HttpException extends Exception { 7 | private final int code; 8 | private final String message; 9 | private final transient ricky.oknet.model.Response response; 10 | 11 | public HttpException(Response response) { 12 | super("HTTP " + response.code() + " " + response.message()); 13 | this.code = response.code(); 14 | this.message = response.message(); 15 | this.response = response; 16 | } 17 | 18 | /** HTTP status code. */ 19 | public int code() { 20 | return code; 21 | } 22 | 23 | /** HTTP status message. */ 24 | public String message() { 25 | return message; 26 | } 27 | 28 | /** 29 | * The full HTTP response. This may be null if the exception was serialized. 30 | */ 31 | public ricky.oknet.model.Response response() { 32 | return response; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/rx/OperatorMapResponseToBodyOrError.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.rx; 2 | 3 | import rx.Observable; 4 | import rx.Observable.Operator; 5 | import rx.Subscriber; 6 | import rx.functions.Func1; 7 | 8 | /** 9 | * A version of {@link Observable#map(Func1)} which lets us trigger {@code onError} without having 10 | * to use {@link Observable#flatMap(Func1)} which breaks producer requests from propagating. 11 | */ 12 | final class OperatorMapResponseToBodyOrError implements Operator> { 13 | 14 | private static final OperatorMapResponseToBodyOrError INSTANCE = new OperatorMapResponseToBodyOrError<>(); 15 | 16 | @SuppressWarnings("unchecked") // Safe because of erasure. 17 | static OperatorMapResponseToBodyOrError instance() { 18 | return (OperatorMapResponseToBodyOrError) INSTANCE; 19 | } 20 | 21 | @Override 22 | public Subscriber> call(final Subscriber child) { 23 | return new Subscriber>(child) { 24 | @Override 25 | public void onNext(ricky.oknet.model.Response response) { 26 | if (response.isSuccessful()) { 27 | child.onNext(response.body()); 28 | } else { 29 | child.onError(new HttpException(response)); 30 | } 31 | } 32 | 33 | @Override 34 | public void onCompleted() { 35 | child.onCompleted(); 36 | } 37 | 38 | @Override 39 | public void onError(Throwable e) { 40 | child.onError(e); 41 | } 42 | }; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/rx/RxAdapter.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.rx; 2 | 3 | import java.util.concurrent.atomic.AtomicBoolean; 4 | 5 | import rx.Observable; 6 | import rx.Producer; 7 | import rx.Subscriber; 8 | import rx.Subscription; 9 | import rx.exceptions.Exceptions; 10 | import rx.schedulers.Schedulers; 11 | 12 | public class RxAdapter implements ricky.oknet.adapter.CallAdapter> { 13 | 14 | public static RxAdapter create() { 15 | return RxAdapter.ConvertHolder.convert; 16 | } 17 | 18 | private static class ConvertHolder { 19 | 20 | private static RxAdapter convert = new RxAdapter(); 21 | } 22 | 23 | @Override 24 | public Observable adapt(ricky.oknet.adapter.Call call) { 25 | return Observable.create(new CallOnSubscribe<>((ricky.oknet.adapter.Call) call)) //强转,本质,T 与 R 是同一个泛型 26 | .subscribeOn(Schedulers.io()) //IO线程订阅网络请求 27 | // .map(new Func1, T>() { 28 | // @Override 29 | // public T call(Response tResponse) { 30 | // return tResponse.body(); 31 | // } 32 | // }); 33 | //感觉用上面的map操作也可以完成,但是Retrofit是这么实现的,目前并不清楚具体好处在哪 34 | .lift(OperatorMapResponseToBodyOrError.instance()); 35 | } 36 | 37 | private static final class CallOnSubscribe implements Observable.OnSubscribe> { 38 | private final ricky.oknet.adapter.Call originalCall; 39 | 40 | CallOnSubscribe(ricky.oknet.adapter.Call originalCall) { 41 | this.originalCall = originalCall; 42 | } 43 | 44 | @Override 45 | public void call(final Subscriber> subscriber) { 46 | // Since Call is a one-shot type, clone it for each new subscriber. 47 | ricky.oknet.adapter.Call call = originalCall.clone(); 48 | 49 | // Wrap the call in a helper which handles both unsubscription and backpressure. 50 | RequestArbiter requestArbiter = new RequestArbiter<>(call, subscriber); 51 | subscriber.add(requestArbiter); 52 | subscriber.setProducer(requestArbiter); 53 | } 54 | } 55 | 56 | private static final class RequestArbiter extends AtomicBoolean implements Subscription, Producer { 57 | private final ricky.oknet.adapter.Call call; 58 | private final Subscriber> subscriber; 59 | 60 | RequestArbiter(ricky.oknet.adapter.Call call, Subscriber> subscriber) { 61 | this.call = call; 62 | this.subscriber = subscriber; 63 | } 64 | 65 | /** 生产事件,将同步请求转化为Rx的事件 */ 66 | @Override 67 | public void request(long n) { 68 | if (n < 0) throw new IllegalArgumentException("n < 0: " + n); 69 | if (n == 0) return; // Nothing to do when requesting 0. 70 | if (!compareAndSet(false, true)) return; // Request was already triggered. 71 | 72 | try { 73 | ricky.oknet.model.Response response = call.execute(); 74 | if (!subscriber.isUnsubscribed()) { 75 | subscriber.onNext(response); 76 | } 77 | } catch (Throwable t) { 78 | Exceptions.throwIfFatal(t); 79 | if (!subscriber.isUnsubscribed()) { 80 | subscriber.onError(t); 81 | } 82 | return; 83 | } 84 | 85 | if (!subscriber.isUnsubscribed()) { 86 | subscriber.onCompleted(); 87 | } 88 | } 89 | 90 | @Override 91 | public void unsubscribe() { 92 | call.cancel(); 93 | } 94 | 95 | @Override 96 | public boolean isUnsubscribed() { 97 | return call.isCanceled(); 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/utils/ApiHelper.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.utils; 2 | 3 | import java.lang.reflect.Proxy; 4 | 5 | import ricky.oknet.retrofit.ApiProxyHandler; 6 | 7 | 8 | @SuppressWarnings("all") 9 | public class ApiHelper { 10 | /** 11 | * @param c 12 | * @param callback 拦截json请求类的回调 13 | * @param Api接口类 14 | * @param 如请求方式为Json时,需要拦截json请求类 15 | * @return 16 | */ 17 | public static T get(Class c, ApiProxyHandler.ICustomerJsonBean... callback) { 18 | return (T) Proxy.newProxyInstance( 19 | c.getClassLoader(), 20 | new Class[]{c}, 21 | new ApiProxyHandler(callback != null && callback.length > 0 ? callback[0] : null)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/utils/Cons.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.utils; 2 | 3 | public interface Cons { 4 | String IO_EXCEPTION = "Canceled"; 5 | String SOCKET_EXCEPTION = "Socket closed"; 6 | } 7 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/utils/DataConvert.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.utils; 2 | 3 | import com.google.gson.FieldNamingPolicy; 4 | import com.google.gson.Gson; 5 | import com.google.gson.GsonBuilder; 6 | import com.google.gson.JsonIOException; 7 | import com.google.gson.JsonSyntaxException; 8 | import com.google.gson.internal.bind.DateTypeAdapter; 9 | import com.google.gson.stream.JsonReader; 10 | 11 | import java.io.Reader; 12 | import java.lang.reflect.Type; 13 | import java.util.Date; 14 | 15 | public class DataConvert { 16 | 17 | private static Gson create() { 18 | return DataConvert.GsonHolder.gson; 19 | } 20 | 21 | private static class GsonHolder { 22 | private static Gson gson = new GsonBuilder() 23 | .setFieldNamingPolicy(FieldNamingPolicy.IDENTITY) 24 | .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") 25 | .enableComplexMapKeySerialization() 26 | .registerTypeAdapter(Date.class, new DateTypeAdapter()) 27 | .create(); 28 | } 29 | 30 | public static T fromJson(String json, Class type) throws JsonIOException, JsonSyntaxException { 31 | return create().fromJson(json, type); 32 | } 33 | 34 | public static T fromJson(String json, Type type) { 35 | return create().fromJson(json, type); 36 | } 37 | 38 | public static T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { 39 | return create().fromJson(reader, typeOfT); 40 | } 41 | 42 | public static T fromJson(Reader json, Class classOfT) throws JsonSyntaxException, JsonIOException { 43 | return create().fromJson(json, classOfT); 44 | } 45 | 46 | public static T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { 47 | return create().fromJson(json, typeOfT); 48 | } 49 | 50 | public static String toJson(Object src) { 51 | return create().toJson(src); 52 | } 53 | 54 | public static String toJson(Object src, Type typeOfSrc) { 55 | return create().toJson(src, typeOfSrc); 56 | } 57 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/utils/Error.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.utils; 2 | 3 | 4 | public enum Error { 5 | NetWork,//net not response or timeout etc 无网、超时等 6 | Internal,//json parse error etc 一般是内部数据解析异常,譬如json解析异常 7 | Server,//404.500 ..etc 8 | UnKnow, 9 | Invalid//request success but no need//token异常等自定义异常,可自行配置 10 | } 11 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/utils/HeaderParser.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.utils; 2 | 3 | import android.text.TextUtils; 4 | 5 | 6 | import java.util.Locale; 7 | import java.util.StringTokenizer; 8 | 9 | import okhttp3.Headers; 10 | import ricky.oknet.cache.CacheEntity; 11 | import ricky.oknet.cache.CacheMode; 12 | import ricky.oknet.model.HttpHeaders; 13 | import ricky.oknet.request.BaseRequest; 14 | 15 | public class HeaderParser { 16 | /** 17 | * 根据请求结果生成对应的缓存实体类,以下为缓存相关的响应头 18 | * Cache-Control: public 响应被缓存,并且在多用户间共享 19 | * Cache-Control: private 响应只能作为私有缓存,不能在用户之间共享 20 | * Cache-Control: no-cache 提醒浏览器要从服务器提取文档进行验证 21 | * Cache-Control: no-store 绝对禁止缓存(用于机密,敏感文件) 22 | * Cache-Control: max-age=60 60秒之后缓存过期(相对时间),优先级比Expires高 23 | * Date: Mon, 19 Nov 2012 08:39:00 GMT 当前response发送的时间 24 | * Expires: Mon, 19 Nov 2012 08:40:01 GMT 缓存过期的时间(绝对时间) 25 | * Last-Modified: Mon, 19 Nov 2012 08:38:01 GMT 服务器端文件的最后修改时间 26 | * ETag: "20b1add7ec1cd1:0" 服务器端文件的ETag值 27 | * 如果同时存在cache-control和Expires,浏览器总是优先使用cache-control 28 | * 29 | * @param responseHeaders 返回数据中的响应头 30 | * @param data 解析出来的数据 31 | * @param cacheMode 缓存的模式 32 | * @param cacheKey 缓存的key 33 | * @return 缓存的实体类 34 | */ 35 | public static CacheEntity createCacheEntity(Headers responseHeaders, T data, CacheMode cacheMode, String cacheKey) { 36 | 37 | long localExpire = 0; // 缓存相对于本地的到期时间 38 | 39 | if (cacheMode == CacheMode.DEFAULT) { 40 | long date = HttpHeaders.getDate(responseHeaders.get(HttpHeaders.HEAD_KEY_DATE)); 41 | long expires = HttpHeaders.getExpiration(responseHeaders.get(HttpHeaders.HEAD_KEY_EXPIRES)); 42 | String cacheControl = HttpHeaders.getCacheControl(responseHeaders.get(HttpHeaders.HEAD_KEY_CACHE_CONTROL), responseHeaders.get(HttpHeaders.HEAD_KEY_PRAGMA)); 43 | 44 | //没有缓存头控制,不需要缓存 45 | if (TextUtils.isEmpty(cacheControl) && expires <= 0) return null; 46 | 47 | long maxAge = 0; 48 | if (!TextUtils.isEmpty(cacheControl)) { 49 | StringTokenizer tokens = new StringTokenizer(cacheControl, ","); 50 | while (tokens.hasMoreTokens()) { 51 | String token = tokens.nextToken().trim().toLowerCase(Locale.getDefault()); 52 | if (token.equals("no-cache") || token.equals("no-store")) { 53 | //服务器指定不缓存 54 | return null; 55 | } else if (token.startsWith("max-age=")) { 56 | try { 57 | //获取最大缓存时间 58 | maxAge = Long.parseLong(token.substring(8)); 59 | //服务器缓存设置立马过期,不缓存 60 | if (maxAge <= 0) return null; 61 | } catch (Exception e) { 62 | OkLogger.e(e); 63 | } 64 | } 65 | } 66 | } 67 | 68 | //获取基准缓存时间,优先使用response中的date头,如果没有就使用本地时间 69 | long now = System.currentTimeMillis(); 70 | if (date > 0) now = date; 71 | 72 | if (maxAge > 0) { 73 | // Http1.1 优先验证 Cache-Control 头 74 | localExpire = now + maxAge * 1000; 75 | } else if (expires >= 0) { 76 | // Http1.0 验证 Expires 头 77 | localExpire = expires; 78 | } 79 | } else { 80 | localExpire = System.currentTimeMillis(); 81 | } 82 | 83 | //将response中所有的头存入 HttpHeaders,原因是写入数据库的对象需要实现序列化,而ok默认的Header没有序列化 84 | HttpHeaders headers = new HttpHeaders(); 85 | for (String headerName : responseHeaders.names()) { 86 | headers.put(headerName, responseHeaders.get(headerName)); 87 | } 88 | 89 | //构建缓存实体对象 90 | CacheEntity cacheEntity = new CacheEntity<>(); 91 | cacheEntity.setKey(cacheKey); 92 | cacheEntity.setData(data); 93 | cacheEntity.setLocalExpire(localExpire); 94 | cacheEntity.setResponseHeaders(headers); 95 | return cacheEntity; 96 | } 97 | 98 | /** 99 | * 对每个请求添加默认的请求头,如果有缓存,并返回缓存实体对象 100 | * Cache-Control: max-age=0 以秒为单位 101 | * If-Modified-Since: Mon, 19 Nov 2012 08:38:01 GMT 缓存文件的最后修改时间。 102 | * If-None-Match: "0693f67a67cc1:0" 缓存文件的ETag值 103 | * Cache-Control: no-cache 不使用缓存 104 | * Pragma: no-cache 不使用缓存 105 | * Accept-Language: zh-CN,zh;q=0.8 支持的语言 106 | * User-Agent: 用户代理,它的信息包括硬件平台、系统软件、应用软件和用户个人偏好 107 | * Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36 108 | * 109 | * @param request 请求类 110 | * @param cacheEntity 缓存实体类 111 | * @param cacheMode 缓存模式 112 | */ 113 | public static void addCacheHeaders(BaseRequest request, CacheEntity cacheEntity, CacheMode cacheMode) { 114 | //1. 按照标准的 http 协议,添加304相关请求头 115 | if (cacheEntity != null && cacheMode == CacheMode.DEFAULT) { 116 | HttpHeaders responseHeaders = cacheEntity.getResponseHeaders(); 117 | if (responseHeaders != null) { 118 | String eTag = responseHeaders.get(HttpHeaders.HEAD_KEY_E_TAG); 119 | if (eTag != null) request.headers(HttpHeaders.HEAD_KEY_IF_NONE_MATCH, eTag); 120 | long lastModified = HttpHeaders.getLastModified(responseHeaders.get(HttpHeaders.HEAD_KEY_LAST_MODIFIED)); 121 | if (lastModified > 0) request.headers(HttpHeaders.HEAD_KEY_IF_MODIFIED_SINCE, HttpHeaders.formatMillisToGMT(lastModified)); 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/utils/HttpUtils.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.utils; 2 | 3 | import android.text.TextUtils; 4 | 5 | 6 | import java.io.File; 7 | import java.io.UnsupportedEncodingException; 8 | import java.net.URLEncoder; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | import okhttp3.FormBody; 13 | import okhttp3.Headers; 14 | import okhttp3.MultipartBody; 15 | import okhttp3.Request; 16 | import okhttp3.RequestBody; 17 | import okhttp3.Response; 18 | import ricky.oknet.model.HttpHeaders; 19 | import ricky.oknet.model.HttpParams; 20 | 21 | public class HttpUtils { 22 | /** 将传递进来的参数拼接成 url */ 23 | public static String createUrlFromParams(String url, Map> params) { 24 | try { 25 | StringBuilder sb = new StringBuilder(); 26 | sb.append(url); 27 | if (url.indexOf('&') > 0 || url.indexOf('?') > 0) sb.append("&"); 28 | else sb.append("?"); 29 | for (Map.Entry> urlParams : params.entrySet()) { 30 | List urlValues = urlParams.getValue(); 31 | for (String value : urlValues) { 32 | //对参数进行 utf-8 编码,防止头信息传中文 33 | String urlValue = URLEncoder.encode(value, "UTF-8"); 34 | sb.append(urlParams.getKey()).append("=").append(urlValue).append("&"); 35 | } 36 | } 37 | sb.deleteCharAt(sb.length() - 1); 38 | return sb.toString(); 39 | } catch (UnsupportedEncodingException e) { 40 | OkLogger.e(e); 41 | } 42 | return url; 43 | } 44 | 45 | /** 通用的拼接请求头 */ 46 | public static Request.Builder appendHeaders(HttpHeaders headers) { 47 | Request.Builder requestBuilder = new Request.Builder(); 48 | if (headers.headersMap.isEmpty()) return requestBuilder; 49 | Headers.Builder headerBuilder = new Headers.Builder(); 50 | try { 51 | for (Map.Entry entry : headers.headersMap.entrySet()) { 52 | //对头信息进行 utf-8 编码,防止头信息传中文,这里暂时不编码,可能出现未知问题,如有需要自行编码 53 | // String headerValue = URLEncoder.encode(entry.getValue(), "UTF-8"); 54 | headerBuilder.add(entry.getKey(), entry.getValue()); 55 | } 56 | } catch (Exception e) { 57 | OkLogger.e(e); 58 | } 59 | requestBuilder.headers(headerBuilder.build()); 60 | return requestBuilder; 61 | } 62 | 63 | /** 生成类似表单的请求体 */ 64 | public static RequestBody generateMultipartRequestBody(HttpParams params, boolean isMultipart) { 65 | if (params.fileParamsMap.isEmpty() && !isMultipart) { 66 | //表单提交,没有文件 67 | FormBody.Builder bodyBuilder = new FormBody.Builder(); 68 | for (String key : params.urlParamsMap.keySet()) { 69 | List urlValues = params.urlParamsMap.get(key); 70 | for (String value : urlValues) { 71 | bodyBuilder.add(key, value); 72 | } 73 | } 74 | return bodyBuilder.build(); 75 | } else { 76 | //表单提交,有文件 77 | MultipartBody.Builder multipartBodybuilder = new MultipartBody.Builder().setType(MultipartBody.FORM); 78 | //拼接键值对 79 | if (!params.urlParamsMap.isEmpty()) { 80 | for (Map.Entry> entry : params.urlParamsMap.entrySet()) { 81 | List urlValues = entry.getValue(); 82 | for (String value : urlValues) { 83 | multipartBodybuilder.addFormDataPart(entry.getKey(), value); 84 | } 85 | } 86 | } 87 | //拼接文件 88 | for (Map.Entry> entry : params.fileParamsMap.entrySet()) { 89 | List fileValues = entry.getValue(); 90 | for (HttpParams.FileWrapper fileWrapper : fileValues) { 91 | RequestBody fileBody = RequestBody.create(fileWrapper.contentType, fileWrapper.file); 92 | multipartBodybuilder.addFormDataPart(entry.getKey(), fileWrapper.fileName, fileBody); 93 | } 94 | } 95 | return multipartBodybuilder.build(); 96 | } 97 | } 98 | 99 | /** 根据响应头或者url获取文件名 */ 100 | public static String getNetFileName(Response response, String url) { 101 | String fileName = getHeaderFileName(response); 102 | if (TextUtils.isEmpty(fileName)) fileName = getUrlFileName(url); 103 | if (TextUtils.isEmpty(fileName)) fileName = "nofilename"; 104 | return fileName; 105 | } 106 | 107 | /** 解析文件头 Content-Disposition:attachment;filename=FileName.txt */ 108 | private static String getHeaderFileName(Response response) { 109 | String dispositionHeader = response.header(HttpHeaders.HEAD_KEY_CONTENT_DISPOSITION); 110 | if (dispositionHeader != null) { 111 | String split = "filename="; 112 | int indexOf = dispositionHeader.indexOf(split); 113 | if (indexOf != -1) { 114 | String fileName = dispositionHeader.substring(indexOf + split.length(), dispositionHeader.length()); 115 | fileName = fileName.replaceAll("\"", ""); //文件名可能包含双引号,需要去除 116 | return fileName; 117 | } 118 | } 119 | return null; 120 | } 121 | 122 | /** 通过 ‘?’ 和 ‘/’ 判断文件名 */ 123 | private static String getUrlFileName(String url) { 124 | int index = url.lastIndexOf('?'); 125 | String filename; 126 | if (index > 1) { 127 | filename = url.substring(url.lastIndexOf('/') + 1, index); 128 | } else { 129 | filename = url.substring(url.lastIndexOf('/') + 1); 130 | } 131 | return filename; 132 | } 133 | 134 | /** 根据路径删除文件 */ 135 | public static boolean deleteFile(String path) { 136 | if (TextUtils.isEmpty(path)) return true; 137 | File file = new File(path); 138 | if (!file.exists()) return true; 139 | if (file.isFile()) { 140 | boolean delete = file.delete(); 141 | OkLogger.e("deleteFile:" + delete + " path:" + path); 142 | return delete; 143 | } 144 | return false; 145 | } 146 | } -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/utils/INoProguard.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016. WorldGo Technology Co., Ltd 3 | * DO NOT DIVULGE 4 | */ 5 | 6 | package ricky.oknet.utils; 7 | 8 | import java.io.Serializable; 9 | 10 | public interface INoProguard extends Serializable { 11 | } 12 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/utils/JsonPrinter.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.utils; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Log; 5 | 6 | import org.json.JSONArray; 7 | import org.json.JSONException; 8 | import org.json.JSONObject; 9 | 10 | /** 11 | * json printer helper 12 | */ 13 | public class JsonPrinter { 14 | 15 | private static final char TOP_LEFT_CORNER = '['; 16 | private static final String DOUBLE_DIVIDER = "--------------------------------------------------"; 17 | private static final char HORIZONTAL_DOUBLE_LINE = '|'; 18 | private static final char BOTTOM_LEFT_CORNER = '['; 19 | private static final String TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER; 20 | private static final String BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER; 21 | private static final int CHUNK_SIZE = 4000; 22 | private static final int JSON_INDENT = 4; 23 | /** 24 | * log tag 25 | */ 26 | public static String TAG = "lays"; 27 | 28 | 29 | public static void json(String json, Runnable r) { 30 | if (TextUtils.isEmpty(json)) { 31 | d("Empty/Null json content"); 32 | return; 33 | } 34 | try { 35 | if (json.startsWith("{")) { 36 | JSONObject jsonObject = new JSONObject(json); 37 | String message = jsonObject.toString(JSON_INDENT); 38 | d(message); 39 | return; 40 | } 41 | if (json.startsWith("[")) { 42 | JSONArray jsonArray = new JSONArray(json); 43 | String message = jsonArray.toString(JSON_INDENT); 44 | d(message); 45 | } 46 | } catch (JSONException ignored) { 47 | if (r != null) r.run(); 48 | } 49 | } 50 | 51 | private static void d(String message, Object... args) { 52 | log(message, args); 53 | } 54 | 55 | private static synchronized void log(String msg, Object... args) { 56 | 57 | String tag = TAG; 58 | String message = createMessage(msg, args); 59 | 60 | Log.i(tag, TOP_BORDER); 61 | 62 | byte[] bytes = message.getBytes(); 63 | int length = bytes.length; 64 | for (int i = 0; i < length; i += CHUNK_SIZE) { 65 | int count = Math.min(length - i, CHUNK_SIZE); 66 | logContent(tag, new String(bytes, i, count)); 67 | } 68 | Log.i(tag, BOTTOM_BORDER); 69 | } 70 | 71 | private static void logContent(String tag, String chunk) { 72 | String[] lines = chunk.split(System.getProperty("line.separator")); 73 | for (String line : lines) { 74 | Log.i(tag, HORIZONTAL_DOUBLE_LINE + " " + line); 75 | } 76 | } 77 | 78 | private static String createMessage(String message, Object... args) { 79 | return args.length == 0 ? message : String.format(message, args); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /oknet/src/main/java/ricky/oknet/utils/OkLogger.java: -------------------------------------------------------------------------------- 1 | package ricky.oknet.utils; 2 | 3 | import android.util.Log; 4 | 5 | public class OkLogger { 6 | public static boolean isLogEnable = true; 7 | 8 | public static String tag = "OkGo"; 9 | 10 | public static void debug(boolean isEnable) { 11 | debug(tag, isEnable); 12 | } 13 | 14 | public static void debug(String logTag, boolean isEnable) { 15 | tag = logTag; 16 | isLogEnable = isEnable; 17 | } 18 | 19 | public static void v(String msg) { 20 | v(tag, msg); 21 | } 22 | 23 | public static void v(String tag, String msg) { 24 | if (isLogEnable) Log.v(tag, msg); 25 | } 26 | 27 | public static void d(String msg) { 28 | d(tag, msg); 29 | } 30 | 31 | public static void d(String tag, String msg) { 32 | if (isLogEnable) Log.d(tag, msg); 33 | } 34 | 35 | public static void i(String msg) { 36 | i(tag, msg); 37 | } 38 | 39 | public static void i(String tag, String msg) { 40 | if (isLogEnable) Log.i(tag, msg); 41 | } 42 | 43 | public static void w(String msg) { 44 | w(tag, msg); 45 | } 46 | 47 | public static void w(String tag, String msg) { 48 | if (isLogEnable) Log.w(tag, msg); 49 | } 50 | 51 | public static void e(String msg) { 52 | e(tag, msg); 53 | } 54 | 55 | public static void e(String tag, String msg) { 56 | if (isLogEnable) Log.e(tag, msg); 57 | } 58 | 59 | public static void e(Throwable t) { 60 | if (isLogEnable) t.printStackTrace(); 61 | } 62 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':oknet' 2 | --------------------------------------------------------------------------------