├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── fatchao │ │ └── rxrequest │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── fatchao │ │ │ └── rxrequest │ │ │ ├── BaseApplication.java │ │ │ ├── MainActivity.java │ │ │ ├── bean │ │ │ ├── LoginBean.java │ │ │ └── OneBean.java │ │ │ ├── callback │ │ │ └── Callback.java │ │ │ ├── constants │ │ │ ├── Constant.java │ │ │ └── RxUrl.java │ │ │ ├── request │ │ │ ├── ProxyHandler.java │ │ │ ├── RequestManager.java │ │ │ ├── RxRequest.java │ │ │ └── RxSubscriber.java │ │ │ └── utils │ │ │ ├── HintUtils.java │ │ │ ├── NetworkManager.java │ │ │ └── PrefUtils.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── fatchao │ └── rxrequest │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | dexOptions { 5 | javaMaxHeapSize "4g" 6 | } 7 | compileSdkVersion 25 8 | buildToolsVersion "25.0.2" 9 | aaptOptions { 10 | cruncherEnabled = false 11 | useNewCruncher = false 12 | } 13 | lintOptions { 14 | checkReleaseBuilds false 15 | // Or, if you prefer, you can continue to check for errors in release builds, 16 | // but continue the build even when errors are found: 17 | abortOnError false 18 | } 19 | configurations.all { 20 | resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9' 21 | } 22 | defaultConfig { 23 | ndk { 24 | abiFilter 'armeabi' 25 | } 26 | applicationId "com.fatchao.rxrequest" 27 | minSdkVersion 16 28 | targetSdkVersion 23 29 | multiDexEnabled true 30 | versionCode 1 31 | versionName "1.2" 32 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 33 | } 34 | 35 | 36 | buildTypes { 37 | release { 38 | minifyEnabled false 39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 40 | } 41 | debug { 42 | } 43 | } 44 | } 45 | 46 | dependencies { 47 | compile fileTree(include: ['*.jar'], dir: 'libs') 48 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 49 | exclude group: 'com.android.support', module: 'support-annotations' 50 | }) 51 | 52 | compile 'com.android.support:support-v4:25.3.0' 53 | compile 'com.squareup.retrofit2:converter-gson:2.1.0' 54 | compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' 55 | compile 'io.reactivex:rxjava:1.1.9' 56 | compile 'io.reactivex:rxandroid:1.2.1' 57 | compile 'com.google.code.gson:gson:2.7' 58 | compile 'com.trello:rxlifecycle:1.0' 59 | compile 'com.trello:rxlifecycle-android:1.0' 60 | compile 'com.trello:rxlifecycle-components:1.0' 61 | compile 'com.android.support:recyclerview-v7:25.3.0' 62 | compile 'com.squareup.okhttp3:logging-interceptor:3.6.0' 63 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7' 64 | } 65 | -------------------------------------------------------------------------------- /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:\l\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 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/fatchao/rxrequest/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.fatchao.rxrequest", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/BaseApplication.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | public class BaseApplication extends Application { 7 | private static Context mContext; 8 | 9 | public static Context getContext() { 10 | return mContext; 11 | } 12 | 13 | 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | mContext = getApplicationContext(); 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.fatchao.rxrequest.bean.OneBean; 8 | import com.fatchao.rxrequest.callback.Callback; 9 | import com.fatchao.rxrequest.request.RequestManager; 10 | import com.fatchao.rxrequest.request.RxRequest; 11 | import com.fatchao.rxrequest.request.RxSubscriber; 12 | import com.trello.rxlifecycle.components.support.RxAppCompatActivity; 13 | 14 | import java.util.HashMap; 15 | 16 | import rx.Observable; 17 | 18 | public class MainActivity extends RxAppCompatActivity { 19 | private TextView tvData; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_main); 25 | iniViews(); 26 | } 27 | 28 | private void iniViews() { 29 | tvData = (TextView) findViewById(R.id.tv_data); 30 | } 31 | 32 | @SuppressWarnings("unchecked") 33 | public void getData(View view) { 34 | HashMap hashMap = new HashMap<>(); 35 | hashMap.put("strDate", "2017-03-25"); 36 | Observable weather = RxRequest.getInstance().getProxy(false).postData(hashMap); 37 | RxSubscriber subscriber = new RxSubscriber(this, new Callback() { 38 | @Override 39 | public void onSuccess(OneBean oneBean) { 40 | tvData.setText(oneBean.getHpEntity().getStrContent()); 41 | } 42 | }); 43 | RequestManager.getInstance().sendRequest(weather, subscriber); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/bean/LoginBean.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.bean; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by fatchao 8 | * 日期 2017-03-31. 9 | * 邮箱 fat_chao@163.com 10 | */ 11 | public class LoginBean implements Serializable { 12 | 13 | private String code; 14 | private String message; 15 | 16 | private DataBean data; 17 | private ProfileBean profile; 18 | 19 | public String getCode() { 20 | return code; 21 | } 22 | 23 | public void setCode(String code) { 24 | this.code = code; 25 | } 26 | 27 | public String getMessage() { 28 | return message; 29 | } 30 | 31 | public void setMessage(String message) { 32 | this.message = message; 33 | } 34 | 35 | public DataBean getData() { 36 | return data; 37 | } 38 | 39 | public void setData(DataBean data) { 40 | this.data = data; 41 | } 42 | 43 | public ProfileBean getProfile() { 44 | return profile; 45 | } 46 | 47 | public void setProfile(ProfileBean profile) { 48 | this.profile = profile; 49 | } 50 | 51 | public static class DataBean { 52 | private String token; 53 | private int expiredSecond; 54 | 55 | public String getToken() { 56 | return token; 57 | } 58 | 59 | public void setToken(String token) { 60 | this.token = token; 61 | } 62 | 63 | public int getExpiredSecond() { 64 | return expiredSecond; 65 | } 66 | 67 | public void setExpiredSecond(int expiredSecond) { 68 | this.expiredSecond = expiredSecond; 69 | } 70 | } 71 | 72 | public static class ProfileBean { 73 | private List type; 74 | 75 | public List getType() { 76 | return type; 77 | } 78 | 79 | public void setType(List type) { 80 | this.type = type; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/bean/OneBean.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by fatchao 7 | * 日期 2017-03-31. 8 | * 邮箱 fat_chao@163.com 9 | */ 10 | 11 | public class OneBean implements Serializable { 12 | 13 | /** 14 | * result : SUCCESS 15 | * hpEntity : {"strLastUpdateDate":"2017-03-31 03:50:13","strDayDiffer":"6","strHpId":"1657","strHpTitle":"VOL.1630","strThumbnailUrl":"http://image.wufazhuce.com/FkJa30EpkRFgPookYi7Uit1y08L5","strOriginalImgUrl":"http://image.wufazhuce.com/FkJa30EpkRFgPookYi7Uit1y08L5","strAuthor":"插画","strContent":"可不想让自己沉溺于虚荣,挣扎于诋毁,磨灭你本该拥有的自在欢愉,真情实性。那你就要记住,知道你自己是谁,比知道他们是谁重要。","strMarketTime":"2017-03-25","sWebLk":"http://m.wufazhuce.com/one/1657","strPn":"","wImgUrl":""} 16 | */ 17 | 18 | private String result; 19 | private HpEntityBean hpEntity; 20 | 21 | public String getResult() { 22 | return result; 23 | } 24 | 25 | public void setResult(String result) { 26 | this.result = result; 27 | } 28 | 29 | public HpEntityBean getHpEntity() { 30 | return hpEntity; 31 | } 32 | 33 | public void setHpEntity(HpEntityBean hpEntity) { 34 | this.hpEntity = hpEntity; 35 | } 36 | 37 | public static class HpEntityBean { 38 | /** 39 | * strLastUpdateDate : 2017-03-31 03:50:13 40 | * strDayDiffer : 6 41 | * strHpId : 1657 42 | * strHpTitle : VOL.1630 43 | * strThumbnailUrl : http://image.wufazhuce.com/FkJa30EpkRFgPookYi7Uit1y08L5 44 | * strOriginalImgUrl : http://image.wufazhuce.com/FkJa30EpkRFgPookYi7Uit1y08L5 45 | * strAuthor : 插画 46 | * strContent : 可不想让自己沉溺于虚荣,挣扎于诋毁,磨灭你本该拥有的自在欢愉,真情实性。那你就要记住,知道你自己是谁,比知道他们是谁重要。 47 | * strMarketTime : 2017-03-25 48 | * sWebLk : http://m.wufazhuce.com/one/1657 49 | * strPn : 50 | * wImgUrl : 51 | */ 52 | 53 | private String strLastUpdateDate; 54 | private String strDayDiffer; 55 | private String strHpId; 56 | private String strHpTitle; 57 | private String strThumbnailUrl; 58 | private String strOriginalImgUrl; 59 | private String strAuthor; 60 | private String strContent; 61 | private String strMarketTime; 62 | private String sWebLk; 63 | private String strPn; 64 | private String wImgUrl; 65 | 66 | public String getStrLastUpdateDate() { 67 | return strLastUpdateDate; 68 | } 69 | 70 | public void setStrLastUpdateDate(String strLastUpdateDate) { 71 | this.strLastUpdateDate = strLastUpdateDate; 72 | } 73 | 74 | public String getStrDayDiffer() { 75 | return strDayDiffer; 76 | } 77 | 78 | public void setStrDayDiffer(String strDayDiffer) { 79 | this.strDayDiffer = strDayDiffer; 80 | } 81 | 82 | public String getStrHpId() { 83 | return strHpId; 84 | } 85 | 86 | public void setStrHpId(String strHpId) { 87 | this.strHpId = strHpId; 88 | } 89 | 90 | public String getStrHpTitle() { 91 | return strHpTitle; 92 | } 93 | 94 | public void setStrHpTitle(String strHpTitle) { 95 | this.strHpTitle = strHpTitle; 96 | } 97 | 98 | public String getStrThumbnailUrl() { 99 | return strThumbnailUrl; 100 | } 101 | 102 | public void setStrThumbnailUrl(String strThumbnailUrl) { 103 | this.strThumbnailUrl = strThumbnailUrl; 104 | } 105 | 106 | public String getStrOriginalImgUrl() { 107 | return strOriginalImgUrl; 108 | } 109 | 110 | public void setStrOriginalImgUrl(String strOriginalImgUrl) { 111 | this.strOriginalImgUrl = strOriginalImgUrl; 112 | } 113 | 114 | public String getStrAuthor() { 115 | return strAuthor; 116 | } 117 | 118 | public void setStrAuthor(String strAuthor) { 119 | this.strAuthor = strAuthor; 120 | } 121 | 122 | public String getStrContent() { 123 | return strContent; 124 | } 125 | 126 | public void setStrContent(String strContent) { 127 | this.strContent = strContent; 128 | } 129 | 130 | public String getStrMarketTime() { 131 | return strMarketTime; 132 | } 133 | 134 | public void setStrMarketTime(String strMarketTime) { 135 | this.strMarketTime = strMarketTime; 136 | } 137 | 138 | public String getSWebLk() { 139 | return sWebLk; 140 | } 141 | 142 | public void setSWebLk(String sWebLk) { 143 | this.sWebLk = sWebLk; 144 | } 145 | 146 | public String getStrPn() { 147 | return strPn; 148 | } 149 | 150 | public void setStrPn(String strPn) { 151 | this.strPn = strPn; 152 | } 153 | 154 | public String getWImgUrl() { 155 | return wImgUrl; 156 | } 157 | 158 | public void setWImgUrl(String wImgUrl) { 159 | this.wImgUrl = wImgUrl; 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/callback/Callback.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.callback; 2 | 3 | import android.util.Log; 4 | 5 | public abstract class Callback { 6 | 7 | public abstract void onSuccess(T t); 8 | 9 | public void onError(Throwable e) { 10 | Log.d("net_error---->", e.toString()); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/constants/Constant.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.constants; 2 | 3 | /** 4 | * Created by fatchao 5 | * 日期 2017-03-31. 6 | * 邮箱 fat_chao@163.com 7 | */ 8 | public class Constant { 9 | public static final String USER_PHONE = "phone"; 10 | public static final String USER_PASSWORD = "password"; 11 | public static String USER_TOKEN = "TOKEN"; 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/constants/RxUrl.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.constants; 2 | 3 | import com.fatchao.rxrequest.bean.LoginBean; 4 | import com.fatchao.rxrequest.bean.OneBean; 5 | 6 | import java.util.Map; 7 | 8 | import retrofit2.http.FieldMap; 9 | import retrofit2.http.FormUrlEncoded; 10 | import retrofit2.http.GET; 11 | import retrofit2.http.POST; 12 | import retrofit2.http.QueryMap; 13 | import rx.Observable; 14 | 15 | /** 16 | * Created by fatchao 17 | * 日期 2017-03-31. 18 | * 邮箱 fat_chao@163.com 19 | */ 20 | public interface RxUrl { 21 | 22 | // ------------服务器地址------------------// 23 | String SERVER_ADDRESS = "http://rest.wufazhuce.com/"; 24 | 25 | //GET请求 26 | @GET("OneForWeb/one/getHpinfo") 27 | Observable getData(@QueryMap Map map); 28 | 29 | 30 | //POST请求 31 | @FormUrlEncoded 32 | @POST("OneForWeb/one/getHpinfo") 33 | Observable postData(@FieldMap Map map); 34 | 35 | 36 | @FormUrlEncoded //登陆 37 | @POST("server/account/common/login.json") 38 | Observable login(@FieldMap Map map); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/request/ProxyHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 david.wei (lighters) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fatchao.rxrequest.request; 18 | /** 19 | * Created by fatchao 20 | * 日期 2017-03-31. 21 | * 邮箱 fat_chao@163.com 22 | */ 23 | import android.accounts.NetworkErrorException; 24 | import android.support.annotation.NonNull; 25 | import android.text.TextUtils; 26 | import android.util.Log; 27 | 28 | import com.fatchao.rxrequest.BaseApplication; 29 | import com.fatchao.rxrequest.bean.LoginBean; 30 | import com.fatchao.rxrequest.constants.Constant; 31 | import com.fatchao.rxrequest.utils.HintUtils; 32 | import com.fatchao.rxrequest.utils.NetworkManager; 33 | import com.fatchao.rxrequest.utils.PrefUtils; 34 | 35 | import java.lang.annotation.Annotation; 36 | import java.lang.reflect.InvocationHandler; 37 | import java.lang.reflect.InvocationTargetException; 38 | import java.lang.reflect.Method; 39 | import java.util.Date; 40 | import java.util.HashMap; 41 | import java.util.Map; 42 | import java.util.concurrent.TimeUnit; 43 | 44 | import okhttp3.CacheControl; 45 | import retrofit2.adapter.rxjava.HttpException; 46 | import retrofit2.http.FieldMap; 47 | import rx.Observable; 48 | import rx.Subscriber; 49 | import rx.functions.Func1; 50 | 51 | 52 | public class ProxyHandler implements InvocationHandler { 53 | private final static int REFRESH_TOKEN_VALID_TIME = 30; 54 | private static long tokenChangedTime = 0; 55 | private Throwable mRefreshTokenError = null; 56 | private boolean mIsTokenNeedRefresh; 57 | private boolean isCache; 58 | 59 | private Object mProxyObject; 60 | private HashMap hashMap = new HashMap<>(); 61 | int cacheTime = 10; 62 | public CacheControl FORCE_CACHE1 = new CacheControl.Builder() 63 | .onlyIfCached() 64 | .maxStale(cacheTime, TimeUnit.SECONDS)//CacheControl.FORCE_CACHE--是int型最大值 65 | .build(); 66 | 67 | public ProxyHandler(Object proxyObject, boolean isCache) { 68 | this.isCache = isCache; 69 | hashMap.put("account", PrefUtils.getString(BaseApplication.getContext(), Constant.USER_PHONE, "")); 70 | hashMap.put("client", "app"); 71 | hashMap.put("password", PrefUtils.getString(BaseApplication.getContext(), Constant.USER_PASSWORD, "")); 72 | mProxyObject = proxyObject; 73 | } 74 | 75 | @Override 76 | public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { 77 | return Observable.just(null).flatMap(new Func1>() { 78 | @Override 79 | public Observable call(Object o) { 80 | if (isCache) { 81 | try { 82 | return (Observable) method.invoke(mProxyObject, args); 83 | } catch (IllegalAccessException e) { 84 | e.printStackTrace(); 85 | } catch (InvocationTargetException e) { 86 | e.printStackTrace(); 87 | } 88 | } else { 89 | if (NetworkManager.isNetworkAvailable(BaseApplication.getContext())) { 90 | try { 91 | try { 92 | if (mIsTokenNeedRefresh) { 93 | Log.d("_t------->", PrefUtils.getString(BaseApplication.getContext(), Constant.USER_TOKEN, "")); 94 | updateMethodToken(method, args); 95 | } 96 | return (Observable) method.invoke(mProxyObject, args); 97 | 98 | } catch (InvocationTargetException e) { 99 | e.printStackTrace(); 100 | } 101 | } catch (IllegalAccessException e) { 102 | e.printStackTrace(); 103 | } 104 | } else { 105 | return Observable.error(new NetworkErrorException()); 106 | } 107 | 108 | } 109 | 110 | return null; 111 | } 112 | }).retryWhen(new Func1, Observable>() { 113 | @Override 114 | public Observable call(Observable observable) { 115 | return observable.flatMap(new Func1>() { 116 | @Override 117 | public Observable call(Throwable throwable) { 118 | if (throwable instanceof HttpException) { 119 | HttpException httpException = (HttpException) throwable; 120 | int code = httpException.code(); 121 | if (code == 401) { 122 | if (PrefUtils.getBoolean(BaseApplication.getContext(), "is402", true)) { 123 | return goToLogin(throwable); 124 | } 125 | return refreshTokenWhenTokenInvalid(); 126 | } else if (code == 402) { 127 | //异地登陆 128 | return goToLogin(throwable); 129 | } else if (code == 502) { 130 | HintUtils.showToast(BaseApplication.getContext(), "服务端正在重启"); 131 | return Observable.error(throwable); 132 | 133 | } else if (code == 504) { 134 | HintUtils.showToast(BaseApplication.getContext(), "缓存读取失败"); 135 | return Observable.error(throwable); 136 | } else { 137 | // HintUtils.showToast(BaseApplication.getContext(), "网络异常,请检查你的网络设置"); 138 | return Observable.error(throwable); 139 | } 140 | } else if (throwable instanceof NetworkErrorException) { 141 | HintUtils.showToast(BaseApplication.getContext(), "网络异常"); 142 | return Observable.error(throwable); 143 | } 144 | return Observable.error(throwable); 145 | 146 | } 147 | }); 148 | } 149 | }); 150 | } 151 | 152 | @NonNull 153 | private Observable goToLogin(Throwable throwable) { 154 | PrefUtils.setBoolean(BaseApplication.getContext(), "is402", true); 155 | HintUtils.showToast(BaseApplication.getContext(), "您的账号已经在另外一台设备上登陆,如果不是本人操作,请尽快修改密码"); 156 | restartApplication(); 157 | return Observable.error(throwable); 158 | } 159 | 160 | 161 | private void restartApplication() { 162 | //TODO 处理异地登陆逻辑 163 | // Intent i = new Intent(); 164 | // i.setClass(BaseApplication.getContext(), LoginActivity.class); 165 | // i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 166 | // BaseApplication.getContext().startActivity(i); 167 | } 168 | 169 | /** 170 | * Refresh the token when the current token is invalid. 171 | * 172 | * @return Observable 173 | */ 174 | private Observable refreshTokenWhenTokenInvalid() { 175 | synchronized (ProxyHandler.class) { 176 | if (new Date().getTime() - tokenChangedTime < REFRESH_TOKEN_VALID_TIME) { 177 | return Observable.just(true); 178 | } else { 179 | RxRequest.getInstance().getProxy(false).login(hashMap) 180 | .subscribe(new Subscriber() { 181 | @Override 182 | public void onCompleted() { 183 | 184 | } 185 | 186 | @Override 187 | public void onError(Throwable e) { 188 | mRefreshTokenError = e; 189 | } 190 | 191 | @Override 192 | public void onNext(LoginBean model) { 193 | if (model != null) { 194 | tokenChangedTime = new Date().getTime(); 195 | PrefUtils.setString(BaseApplication.getContext(), Constant.USER_TOKEN, model.getData().getToken()); 196 | Log.d("token-----put------>", PrefUtils.getString(BaseApplication.getContext(), Constant.USER_TOKEN, "")); 197 | mIsTokenNeedRefresh = true; 198 | } 199 | } 200 | }); 201 | } 202 | if (mRefreshTokenError != null) { 203 | return Observable.error(mRefreshTokenError); 204 | } else { 205 | return Observable.just(true); 206 | } 207 | 208 | } 209 | } 210 | 211 | private void updateMethodToken(Method method, Object[] args) { 212 | if (mIsTokenNeedRefresh && !TextUtils.isEmpty(PrefUtils.getString(BaseApplication.getContext(), Constant.USER_TOKEN, ""))) { 213 | Annotation[][] annotationsArray = method.getParameterAnnotations(); 214 | Annotation[] annotations; 215 | if (annotationsArray != null && annotationsArray.length > 0) { 216 | for (int i = 0; i < annotationsArray.length; i++) { 217 | annotations = annotationsArray[i]; 218 | for (Annotation annotation : annotations) { 219 | if (annotation instanceof FieldMap) { 220 | HashMap hashMap = (HashMap) args[i]; 221 | for (Map.Entry stringStringEntry : hashMap.entrySet()) { 222 | if (stringStringEntry.getKey().equals("_t")) { 223 | hashMap.put("_t", PrefUtils.getString(BaseApplication.getContext(), Constant.USER_TOKEN, "")); 224 | } 225 | } 226 | args[i] = hashMap; 227 | // 228 | } 229 | //Get请求遍历方式 230 | // if (annotation instanceof Query) { 231 | // if (TOKEN.equals(((Query) annotation).value())) { 232 | // args[i] = GlobalToken.getToken(); 233 | // } 234 | // } 235 | } 236 | } 237 | } 238 | mIsTokenNeedRefresh = false; 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/request/RequestManager.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.request; 2 | 3 | import com.trello.rxlifecycle.android.ActivityEvent; 4 | 5 | import rx.Observable; 6 | import rx.android.schedulers.AndroidSchedulers; 7 | import rx.schedulers.Schedulers; 8 | /** 9 | * Created by fatchao 10 | * 日期 2017-03-31. 11 | * 邮箱 fat_chao@163.com 12 | */ 13 | @SuppressWarnings("unchecked") 14 | public class RequestManager { 15 | private volatile static RequestManager INSTANCE; 16 | 17 | //构造方法私有 18 | private RequestManager() { 19 | } 20 | 21 | //获取单例 22 | public static RequestManager getInstance() { 23 | if (INSTANCE == null) { 24 | synchronized (RequestManager.class) { 25 | if (INSTANCE == null) { 26 | INSTANCE = new RequestManager(); 27 | } 28 | } 29 | } 30 | return INSTANCE; 31 | } 32 | 33 | public void sendRequest(Observable observable, RxSubscriber subscriber) { 34 | if (observable != null) 35 | observable.compose(subscriber.getActivity().bindToLifecycle())//绑定生命周期 36 | .compose(subscriber.getActivity().bindUntilEvent(ActivityEvent.DESTROY)) 37 | .subscribeOn(Schedulers.io())//操作线程 38 | .unsubscribeOn(Schedulers.io())//解绑线程 39 | .observeOn(AndroidSchedulers.mainThread())//回调线程 40 | .subscribe(subscriber); 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/request/RxRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.fatchao.rxrequest.request; 3 | 4 | import android.os.Build; 5 | import android.util.Log; 6 | 7 | import com.fatchao.rxrequest.BaseApplication; 8 | import com.fatchao.rxrequest.constants.RxUrl; 9 | import com.fatchao.rxrequest.utils.NetworkManager; 10 | 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.lang.reflect.Proxy; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | import okhttp3.Cache; 17 | import okhttp3.CacheControl; 18 | import okhttp3.Interceptor; 19 | import okhttp3.OkHttpClient; 20 | import okhttp3.Request; 21 | import okhttp3.Response; 22 | import okhttp3.logging.HttpLoggingInterceptor; 23 | import retrofit2.Retrofit; 24 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 25 | import retrofit2.converter.gson.GsonConverterFactory; 26 | 27 | import static okhttp3.CacheControl.FORCE_CACHE; 28 | 29 | /** 30 | * Created by fatchao 31 | * 日期 2017-03-31. 32 | * 邮箱 fat_chao@163.com 33 | */ 34 | @SuppressWarnings("unchecked") 35 | 36 | public class RxRequest { 37 | private static Retrofit sRetrofit, cacheRetrofit; 38 | private static OkHttpClient sOkHttpClient, cacheOkhttpClient; 39 | private static RxRequest instance; 40 | private final static Object mRetrofitLock = new Object(); 41 | private boolean isCache; 42 | //这是设置在多长时间范围内获取缓存里面 43 | public static int cacheTime = 10; 44 | public static CacheControl FORCE_CACHE1 = new CacheControl.Builder() 45 | .onlyIfCached() 46 | .maxStale(cacheTime, TimeUnit.SECONDS)//CacheControl.FORCE_CACHE--是int型最大值 47 | .build(); 48 | 49 | 50 | //get请求缓存(不带token) 51 | private static Retrofit getCacheRetrofit() { 52 | if (cacheRetrofit == null) { 53 | synchronized (mRetrofitLock) { 54 | if (cacheRetrofit == null) { 55 | //设置缓存 56 | File httpCacheDirectory = new File(BaseApplication.getContext().getCacheDir(), "tajiaCache"); 57 | Cache cache = null; 58 | try { 59 | cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024); 60 | } catch (Exception e) { 61 | Log.e("OKHttp", "Could not create http cache", e); 62 | } 63 | Interceptor interceptor = new Interceptor() { 64 | @Override 65 | public Response intercept(Chain chain) throws IOException { 66 | Request request = chain.request(); 67 | if (NetworkManager.isNetworkAvailable(BaseApplication.getContext())) {//有网时 68 | Response response = chain.proceed(request); 69 | String cacheControl = request.cacheControl().toString(); 70 | Log.e("yjbo-cache", "在线缓存在1分钟内可读取" + cacheControl); 71 | return response.newBuilder() 72 | .removeHeader("Pragma") 73 | .removeHeader("Cache-Control") 74 | .header("Cache-Control", "public, max-age=" + 0) 75 | .build(); 76 | } else { 77 | //无网时 78 | request = request.newBuilder() 79 | .cacheControl(FORCE_CACHE)//此处不设置过期时间 80 | .build(); 81 | Response response = chain.proceed(request); 82 | //下面注释的部分设置也没有效果,因为在上面已经设置了 83 | return response.newBuilder() 84 | .header("Cache-Control", "public, only-if-cached") 85 | .removeHeader("Pragma") 86 | .build(); 87 | } 88 | 89 | } 90 | 91 | }; 92 | OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder(); 93 | HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); 94 | httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 95 | clientBuilder 96 | .cache(cache) 97 | .addInterceptor(httpLoggingInterceptor) 98 | .addInterceptor(interceptor) 99 | .addNetworkInterceptor(interceptor); 100 | cacheOkhttpClient = clientBuilder 101 | .addInterceptor(new Interceptor() { 102 | @Override 103 | public Response intercept(Chain chain) throws IOException { 104 | String header = Build.DEVICE + "-" + Build.BRAND + "-" + Build.MODEL + "-" + Build.VERSION.RELEASE + "-" + Build.TIME + "-" + Build.VERSION.INCREMENTAL; 105 | Request request = chain.request() 106 | .newBuilder() 107 | .addHeader("User-Agent", header) 108 | .build(); 109 | return chain.proceed(request); 110 | } 111 | }) 112 | .build(); 113 | cacheRetrofit = new Retrofit.Builder().client(cacheOkhttpClient) 114 | .baseUrl(RxUrl.SERVER_ADDRESS) 115 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 116 | .addConverterFactory(GsonConverterFactory.create()) 117 | .build(); 118 | } 119 | } 120 | } 121 | return cacheRetrofit; 122 | } 123 | 124 | 125 | //post请求不缓存 126 | 127 | private static Retrofit getRetrofit() { 128 | if (sRetrofit == null) { 129 | synchronized (mRetrofitLock) { 130 | if (sRetrofit == null) { 131 | OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder(); 132 | HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); 133 | httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 134 | clientBuilder.addInterceptor(httpLoggingInterceptor); 135 | sOkHttpClient = clientBuilder 136 | .addInterceptor(new Interceptor() { 137 | @Override 138 | public Response intercept(Chain chain) throws IOException { 139 | String header = Build.DEVICE + "-" + Build.BRAND + "-" + Build.MODEL + "-" + Build.VERSION.RELEASE + "-" + Build.TIME + "-" + Build.VERSION.INCREMENTAL; 140 | Request request = chain.request() 141 | .newBuilder() 142 | .addHeader("User-Agent", header) 143 | .build(); 144 | return chain.proceed(request); 145 | } 146 | }) 147 | .build(); 148 | sRetrofit = new Retrofit.Builder().client(sOkHttpClient) 149 | .baseUrl(RxUrl.SERVER_ADDRESS) 150 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 151 | .addConverterFactory(GsonConverterFactory.create()) 152 | .build(); 153 | } 154 | } 155 | } 156 | return sRetrofit; 157 | } 158 | 159 | 160 | //获取请求类实例 161 | public static RxRequest getInstance() { 162 | if (instance == null) { 163 | synchronized (RxRequest.class) { 164 | if (instance == null) { 165 | instance = new RxRequest(); 166 | } 167 | } 168 | } 169 | return instance; 170 | } 171 | 172 | 173 | public RxUrl getProxy(boolean isCache) { 174 | RxUrl mRxUrl = null; 175 | if (isCache) { 176 | mRxUrl = getCacheRetrofit().create(RxUrl.class); 177 | } else { 178 | mRxUrl = getRetrofit().create(RxUrl.class); 179 | } 180 | return (RxUrl) Proxy.newProxyInstance(RxUrl.class.getClassLoader(), new Class[]{RxUrl.class}, new ProxyHandler(mRxUrl, false)); 181 | } 182 | 183 | 184 | } 185 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/request/RxSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.request; 2 | 3 | import com.fatchao.rxrequest.callback.Callback; 4 | import com.trello.rxlifecycle.components.support.RxAppCompatActivity; 5 | 6 | import java.lang.ref.SoftReference; 7 | 8 | import rx.Subscriber; 9 | 10 | /** 11 | * Created by fatchao 12 | * 日期 2017-03-31. 13 | * 邮箱 fat_chao@163.com 14 | */ 15 | @SuppressWarnings("unchecked") 16 | public class RxSubscriber extends Subscriber { 17 | private SoftReference rxListener; 18 | private SoftReference mActivity; 19 | 20 | public RxSubscriber(RxAppCompatActivity rxAppCompatActivity, Callback listener) { 21 | this.mActivity = new SoftReference(rxAppCompatActivity); 22 | this.rxListener = new SoftReference(listener); 23 | } 24 | 25 | @Override 26 | public void onStart() { 27 | //TODO 可是做一些初始化操作,比如说谈一个对话框或者进度条 28 | } 29 | 30 | @Override 31 | public void onNext(T t) { 32 | if (rxListener.get() != null) { 33 | rxListener.get().onSuccess(t); 34 | } 35 | } 36 | 37 | @Override 38 | public void onCompleted() { 39 | //TODO 请求完成时走此方法 40 | 41 | } 42 | 43 | @Override 44 | public void onError(Throwable e) { 45 | // TODO 请求发生错误时走此方法 46 | if (rxListener.get() != null) { 47 | rxListener.get().onError(e); 48 | } 49 | } 50 | 51 | 52 | public RxAppCompatActivity getActivity() { 53 | return mActivity.get(); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/utils/HintUtils.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.utils; 2 | 3 | import android.content.Context; 4 | import android.os.Looper; 5 | import android.view.Gravity; 6 | import android.widget.Toast; 7 | 8 | public class HintUtils { 9 | 10 | /** 11 | * 弹出信息 12 | * 13 | * @param context 14 | * @param msg 15 | */ 16 | public static void showToast(final Context context, final String msg) { 17 | // Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); 18 | new Thread(new Runnable() { 19 | @Override 20 | public void run() { 21 | Looper.prepare(); 22 | Toast toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT); 23 | toast.setGravity(Gravity.CENTER, 0, 0); 24 | toast.show(); 25 | Looper.loop(); 26 | } 27 | }).start(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/utils/NetworkManager.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.utils; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | public class NetworkManager { 8 | /** 9 | * 判断当前网络可不可用 10 | * 11 | * @param context 12 | * @return 13 | */ 14 | public static boolean isNetworkAvailable(Context context) { 15 | ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 16 | if (cm == null) { 17 | return false; 18 | } else { 19 | NetworkInfo info = cm.getActiveNetworkInfo(); 20 | if (info != null && info.getState() == NetworkInfo.State.CONNECTED) 21 | return true; 22 | else 23 | return false; 24 | } 25 | } 26 | 27 | /*** 28 | * 检查网络 29 | * 30 | * @param context 31 | * @return 32 | */ 33 | public static boolean checkNet(Context context) { 34 | try { 35 | ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 36 | if (connectivity != null) { 37 | // 获取网络连接管理的对像 38 | NetworkInfo info = connectivity.getActiveNetworkInfo(); 39 | if (info == null || !info.isAvailable()) { 40 | return false; 41 | } else { 42 | return true; 43 | } 44 | } 45 | } catch (Exception e) { 46 | e.printStackTrace(); 47 | } 48 | return false; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/fatchao/rxrequest/utils/PrefUtils.java: -------------------------------------------------------------------------------- 1 | package com.fatchao.rxrequest.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | /** 7 | * @author Administrator 8 | * SharePreference工具 9 | */ 10 | public class PrefUtils { 11 | 12 | public static final String PREF_NAME = "config"; 13 | 14 | public static boolean getBoolean(Context ctx, String key, 15 | boolean defaultValue) { 16 | SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, 17 | Context.MODE_PRIVATE); 18 | return sp.getBoolean(key, defaultValue); 19 | } 20 | 21 | public static void setBoolean(Context ctx, String key, boolean value) { 22 | SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, 23 | Context.MODE_PRIVATE); 24 | sp.edit().putBoolean(key, value).commit(); 25 | } 26 | 27 | public static String getString(Context ctx, String key, String defaultValue) { 28 | SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, 29 | Context.MODE_PRIVATE); 30 | return sp.getString(key, defaultValue); 31 | } 32 | 33 | public static int getInt(Context ctx, String key, int defaultValue) { 34 | SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, 35 | Context.MODE_PRIVATE); 36 | return sp.getInt(key, defaultValue); 37 | } 38 | 39 | public static void setString(Context ctx, String key, String value) { 40 | SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, 41 | Context.MODE_PRIVATE); 42 | sp.edit().putString(key, value).commit(); 43 | } 44 | 45 | public static void setInt(Context ctx, String key, int value) { 46 | SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, 47 | Context.MODE_PRIVATE); 48 | sp.edit().putInt(key, value).commit(); 49 | } 50 | 51 | public static void clear(Context ctx) { 52 | SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME, 53 | Context.MODE_PRIVATE); 54 | sp.edit().clear().apply(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 |