Retrofit的优点

  1. 可以配置不同HTTP client来实现网络请求,如okhttp、httpclient等
  2. 将接口的定义与使用分离开来,实现结构。
  3. 支持多种返回数据解析的Converter可以快速进行数据转换。
  4. 和RxJava集成的很好
  5. 因为容易和RxJava结合使用,所以对于异步请求,同步请求也不需要做额外的工作。
  6. Retrofit是基于OKHttp

简单使用

配置依赖

在module的build.gradle中添加

  1. // Retrofit
  2. api "com.squareup.retrofit2:retrofit:2.3.0"
  3. api "com.squareup.retrofit2:converter-gson:2.3.0"
  4. api "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
  5. // OkHttp3
  6. api "com.squareup.okhttp3:okhttp:3.10.0"
  7. api "com.squareup.okhttp3:logging-interceptor:3.10.0"
  8. // RxJava2
  9. api "io.reactivex.rxjava2:rxjava:2.1.9"
  10. api "io.reactivex.rxjava2:rxandroid:2.0.2"
  11. // RxLifecycle
  12. api "com.trello.rxlifecycle2:rxlifecycle:2.2.1"
  13. api "com.trello.rxlifecycle2:rxlifecycle-android:2.2.1"
  14. api "com.trello.rxlifecycle2:rxlifecycle-components:2.2.1"
定义Retrofit单例

在Application中初始化Retrofit,因为一个Retrofit对象本身就包含一个线程池,所以我们可以初始化一个Retrofit对象,并将其做成一个全局单例对象

  1. /**
  2. * Retrofit单例管理
  3. * Created by Leon.W on 2019/4/28
  4. */
  5. public class RetrofitManager {
  6. private final String BASE_URL = "https://api.github.com";
  7. private static RetrofitManager sInstance;
  8. private Retrofit mRetrofit;
  9. public static RetrofitManager getInstance() {
  10. if (null == sInstance) {
  11. synchronized (RetrofitManager.class) {
  12. if (null == sInstance) {
  13. sInstance = new RetrofitManager();
  14. }
  15. }
  16. }
  17. return sInstance;
  18. }
  19. public void init() {
  20. if(mRetrofit == null) {
  21. //初始化一个OkHttpClient
  22. OkHttpClient.Builder builder = new OkHttpClient.Builder()
  23. .connectTimeout(30000, TimeUnit.MILLISECONDS)
  24. .readTimeout(30000, TimeUnit.MILLISECONDS)
  25. .writeTimeout(30000, TimeUnit.MILLISECONDS);
  26. builder.addInterceptor(new LoggingInterceptor());
  27. OkHttpClient okHttpClient = builder.build();
  28. //使用该OkHttpClient创建一个Retrofit对象
  29. mRetrofit = new Retrofit.Builder()
  30. //添加Gson数据格式转换器支持
  31. .addConverterFactory(GsonConverterFactory.create())
  32. //添加RxJava语言支持
  33. .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  34. //指定网络请求client
  35. .client(okHttpClient)
  36. .baseUrl(BASE_URL)
  37. .build();
  38. }
  39. }
  40. public Retrofit getRetrofit() {
  41. if(mRetrofit == null) {
  42. throw new IllegalStateException("Retrofit instance hasn't init!");
  43. }
  44. return mRetrofit;
  45. }
  46. }
定义ApiService
  1. //ApiService.java
  2. public interface ApiService {
  3. @GET("/TP_S/BookList")
  4. Observable<JsonArrayBase<Book>> queryBookList();
  5. }
定义接口方法实现方法
  1. //GithubAPI.java
  2. public class GithubAPI {
  3. Observable<GithubUserInfo> queryJakeWhartonInfo() {
  4. return RetrofitManager.getInstance().getRetrofit()
  5. //动态代理创建GithubAPI对象
  6. .create(ApiService.class)
  7. .queryJakeWhartonInfo()
  8. //指定上游发送事件线程
  9. .subscribeOn(Schedulers.computation())
  10. //指定下游接收事件线程
  11. .observeOn(AndroidSchedulers.mainThread());
  12. }
  13. }
定义返回数据实体类
  1. public class GithubUserInfo {
  2. String login,url,name,company;
  3. int id,public_repos,followers;
  4. @Override
  5. public String toString() {
  6. return "GithubUserInfo{" +
  7. "login='" + login + '\'' +
  8. ", url='" + url + '\'' +
  9. ", name='" + name + '\'' +
  10. ", company='" + company + '\'' +
  11. ", id=" + id +
  12. ", public_repos=" + public_repos +
  13. ", followers=" + followers +
  14. '}';
  15. }
  16. }
调用接口
  1. new GithubAPI().queryJakeWhartonInfo().subscribe(new Observer<GithubUserInfo>() {
  2. @Override
  3. public void onSubscribe(Disposable d) {
  4. }
  5. @Override
  6. public void onNext(GithubUserInfo githubUserInfo) {
  7. Log.d(TAG,githubUserInfo.toString());
  8. }
  9. @Override
  10. public void onError(Throwable e) {
  11. e.printStackTrace();
  12. Log.e(TAG,e.getMessage());
  13. }
  14. @Override
  15. public void onComplete() {
  16. }
  17. });
  18. >>>输出:
  19. D/TestRetrofit: GithubUserInfo{login='JakeWharton', url='https://api.github.com/users/JakeWharton', name='Jake Wharton', company='Google, Inc.', id=66577, public_repos=102, followers=52467}

异常处理

请求过程中的异常一般分为2种类型,一种是类似网络异常、服务器这种环境问题;另一种比如请求参数错误、登录超时、Token失效等异常。分别做如下处理

环境问题

环境异常诸如404、500、502等服务器状态异常,或者设备本身网路异常造成的,这种时候的Exception会在onError方法中得到响应。

数据问题

数据问题诸如请求参数异常、对象为空、登录超时等数据相关异常,这种情况Response还是会走onNext方法,只是我们需要在里面根据自定义的code,来处理各种数据异常。
下面是一个具体的基础Observer类,在其onNext中解析
一般服务器接口返回数据会约定一个简单的格式:

  1. {
  2. code:int,
  3. msg:String,
  4. data:{} //可能是对象,有可能是数组data:[]
  5. }

对应的建议解析类,一般当接口返回先解析其code是否为成功,如果不是,那看看是否是特定的错误码,把错误码code和错误信息msg包装成一个自定义的Exception进行处理。如果成功,则对返回结果进行进一步的解析,针对不同的接口解析成“对象”或者“数组”。

  1. //JsonBase.java,解析code和msg
  2. public class JsonBase implements Serializable{
  3. private static final long serialVersionUID = -6182189632617616248L;
  4. @SerializedName("msg")
  5. private String msg;
  6. private int code = -1;
  7. public int getCode() {
  8. return code;
  9. }
  10. public void setCode(int code) {
  11. this.code = code;
  12. }
  13. public String getMsg() {
  14. return msg;
  15. }
  16. public void setMsg(String msg) {
  17. this.msg = msg;
  18. }
  19. }
  1. //JsonArrayBase.java,解析数组类型
  2. public class JsonArrayBase<T> extends JsonBase {
  3. @SerializedName("data")
  4. List<T> data;
  5. public List<T> getData() {
  6. return data;
  7. }
  8. public void setData(List<T> data) {
  9. this.data = data;
  10. }
  11. @Override
  12. public String toString() {
  13. StringBuilder sb = new StringBuilder();
  14. for(int i = 0; i< data.size(); i++) {
  15. sb.append(data.get(i).toString());
  16. }
  17. return sb.toString();
  18. }
  19. }
  1. //JsonObjBase.java,解析对象类型
  2. public class JsonObjBase<T> extends JsonBase {
  3. @SerializedName("data")
  4. T data;
  5. public T getData() {
  6. return data;
  7. }
  8. public void setData(T data) {
  9. this.data = data;
  10. }
  11. }

基础Observer,用于处理数据异常(即code不是SUCC的情况);网络异常(在onError方法中进行toast提示),具体使用界面可以通过重写onError来得到回调(比如分页加载失败,需要隐藏加载进度条,此时需要得到失败回调)

  1. //BaseObserver.java
  2. public abstract class BaseObserver<T> implements Observer<T> {
  3. private String TAG = "BaseObserver";
  4. @Override
  5. public void onNext(T t) {
  6. if (t == null) {
  7. onError(HttpCode.ERROR_EMPTY_OBJ, getErrorMessage(HttpCode.ERROR_EMPTY_OBJ));
  8. } else {
  9. onSuccess(t);
  10. }
  11. }
  12. /**
  13. * 外部想要处理异常(比如分页加载失败,需要隐藏加载中效果)时,可以重写该方法
  14. */
  15. public void onError(int errorCode, String message) {
  16. }
  17. /**
  18. * 外部重写,接受数据
  19. * @param t
  20. */
  21. public abstract void onSuccess(T t);
  22. /**
  23. * 不显示服务器返回错误信息(部分接口返回不规范)
  24. */
  25. public boolean isShowErrorToast() {
  26. return true;
  27. }
  28. @Override
  29. public void onError(Throwable e) {
  30. int errorCode = -1;
  31. String errMsg = "";
  32. //自定义异常
  33. if (e instanceof MyException) {
  34. MyException exception = (MyException) e;
  35. errorCode = exception.getErrorCode();
  36. errMsg = exception.getMessage();
  37. handleIybErrorCode(errorCode);
  38. if (isShowErrorToast()) {
  39. Toast.makeText(TestAPP.getInstance().getApplicationContext(), errMsg,Toast.LENGTH_LONG).show();
  40. }
  41. } else if (e instanceof NullPointerException) { // RxJava2 发送值为null时,不执行 onNext,直接走 onError
  42. errorCode = HttpCode.ERROR_EMPTY_OBJ;
  43. errMsg = getErrorMessage(HttpCode.ERROR_EMPTY_OBJ);
  44. } else if (e instanceof SocketTimeoutException) {
  45. errorCode = HttpCode.ERROR_TIMEOUT;
  46. errMsg = getErrorMessage(HttpCode.ERROR_TIMEOUT);
  47. Toast.makeText(TestAPP.getInstance().getApplicationContext(), errMsg,Toast.LENGTH_LONG).show();
  48. } else if (e instanceof NetworkErrorException) {
  49. errorCode = HttpCode.ERROR_NETWORK;
  50. errMsg = getErrorMessage(HttpCode.ERROR_NETWORK);
  51. Toast.makeText(TestAPP.getInstance().getApplicationContext(), errMsg,Toast.LENGTH_LONG).show();
  52. } else if (e instanceof HttpException) {
  53. HttpException httpException = (HttpException) e;
  54. errMsg = httpException != null ? httpException.getMessage() : getErrorMessage(HttpCode.ERROR_SERVER_EXCEPTION);
  55. int httpErrorCode = httpException != null ? httpException.code() : HttpCode.ERROR_UNKNOWN;
  56. Log.d(TAG, "Http request error:" + "message=" + errMsg + " :::: " + "httpErrorCode=" + httpErrorCode);
  57. Toast.makeText(TestAPP.getInstance().getApplicationContext(), getErrorMessage(HttpCode.ERROR_SERVER_EXCEPTION),Toast.LENGTH_LONG).show(); // 统一提示服务器异常
  58. } else {
  59. errMsg = e != null ? e.getMessage() : getErrorMessage(HttpCode.ERROR_UNKNOWN);
  60. }
  61. onError(errorCode, errMsg);
  62. }
  63. /**
  64. * 处理数据异常code
  65. * @param errorCode
  66. */
  67. private void handleIybErrorCode(int errorCode) {
  68. if (errorCode == HttpCode.ERROR_ALREADY_REGISTER) {
  69. //已注册处理逻辑
  70. } else if (errorCode == HttpCode.ERROR_LOGIN_EXPIRED ) {
  71. //登录超时处理逻辑
  72. }
  73. }
  74. private String getErrorMessage(int errorCode) {
  75. String message = HttpCode.ERRORS.get(errorCode);
  76. if (TextUtils.isEmpty(message)) {
  77. message = HttpCode.ERRORS.get(HttpCode.ERROR_UNKNOWN);
  78. }
  79. return message;
  80. }
  81. }
  1. public abstract class BaseObserver<T> implements Observer<T> {
  2. private String TAG = "BaseObserver";
  3. @Override
  4. public void onNext(T t) {
  5. if (t == null) {
  6. onError(HttpCode.ERROR_EMPTY_OBJ, getErrorMessage(HttpCode.ERROR_EMPTY_OBJ));
  7. } else {
  8. onSuccess(t);
  9. }
  10. }
  11. /**外部想要处理异常时(比如分页加载失败,需要隐藏加载中效果),可以重写该方法*/
  12. public void onError(int errorCode, String message) {
  13. }
  14. public abstract void onSuccess(T t);
  15. /** 不显示服务器返回错误信息(部分接口返回不规范) */
  16. public boolean isShowErrorToast() {
  17. return true;
  18. }
  19. @Override
  20. public void onError(Throwable e) {
  21. int errorCode = -1;
  22. String errMsg = "";
  23. //自定义异常
  24. if (e instanceof MyException) {
  25. MyException exception = (MyException) e;
  26. errorCode = exception.getErrorCode();
  27. errMsg = exception.getMessage();
  28. handleErrorCode(errorCode);
  29. if (isShowErrorToast()) {
  30. Toast.makeText(TestAPP.getInstance().getApplicationContext(), errMsg,Toast.LENGTH_LONG).show();
  31. }
  32. } else if (e instanceof NullPointerException) { // RxJava2 发送值为null时,不执行 onNext,直接走 onError
  33. errorCode = HttpCode.ERROR_EMPTY_OBJ;
  34. errMsg = getErrorMessage(HttpCode.ERROR_EMPTY_OBJ);
  35. } else if (e instanceof SocketTimeoutException) {
  36. errorCode = HttpCode.ERROR_TIMEOUT;
  37. errMsg = getErrorMessage(HttpCode.ERROR_TIMEOUT);
  38. Toast.makeText(TestAPP.getInstance().getApplicationContext(), errMsg,Toast.LENGTH_LONG).show();
  39. } else if (e instanceof NetworkErrorException) {
  40. errorCode = HttpCode.ERROR_NETWORK;
  41. errMsg = getErrorMessage(HttpCode.ERROR_NETWORK);
  42. Toast.makeText(TestAPP.getInstance().getApplicationContext(), errMsg,Toast.LENGTH_LONG).show();
  43. } else if (e instanceof HttpException) {
  44. HttpException httpException = (HttpException) e;
  45. errMsg = httpException != null ? httpException.getMessage() : getErrorMessage(HttpCode.ERROR_SERVER_EXCEPTION);
  46. int httpErrorCode = httpException != null ? httpException.code() : HttpCode.ERROR_UNKNOWN;
  47. Log.d(TAG, "Http request error:" + "message=" + errMsg + " :::: " + "httpErrorCode=" + httpErrorCode);
  48. Toast.makeText(TestAPP.getInstance().getApplicationContext(), getErrorMessage(HttpCode.ERROR_SERVER_EXCEPTION),Toast.LENGTH_LONG).show(); // 统一提示服务器异常
  49. } else {
  50. errMsg = e != null ? e.getMessage() : getErrorMessage(HttpCode.ERROR_UNKNOWN);
  51. Toast.makeText(TestAPP.getInstance().getApplicationContext(), e.getMessage(),Toast.LENGTH_LONG).show(); // 统一提示服务器异常
  52. }
  53. onError(errorCode, errMsg);
  54. }
  55. /**
  56. * 处理数据异常code
  57. * @param errorCode
  58. */
  59. private void handleErrorCode(int errorCode) {
  60. if (errorCode == HttpCode.ERROR_ALREADY_REGISTER) {
  61. //已注册处理逻辑
  62. } else if (errorCode == HttpCode.ERROR_LOGIN_EXPIRED ) {
  63. //登录超时处理逻辑
  64. }
  65. }
  66. private String getErrorMessage(int errorCode) {
  67. String message = HttpCode.ERRORS.get(errorCode);
  68. if (TextUtils.isEmpty(message)) {
  69. message = HttpCode.ERRORS.get(HttpCode.ERROR_UNKNOWN);
  70. }
  71. return message;
  72. }
  73. }
  1. //MyException.java
  2. public class MyException extends Exception {
  3. private int mErrorCode;
  4. private String mMessage;
  5. public MyException(int errorCode, String message) {
  6. super();
  7. mErrorCode = errorCode;
  8. mMessage = message;
  9. }
  10. public int getErrorCode() {
  11. return mErrorCode;
  12. }
  13. public void setErrorCode(int mErrorCode) {
  14. this.mErrorCode = mErrorCode;
  15. }
  16. public String getMessage() {
  17. return mMessage;
  18. }
  19. public void setMessage(String message) {
  20. this.mMessage = message;
  21. }
  22. }
  1. public class HttpCode {
  2. public static final int ERROR_UNKNOWN = -1;
  3. public static final int ERROR_SUCCESS = 0;
  4. // 1000~1099 自定义错误码
  5. public static final int ERROR_NETWORK = 1000;
  6. public static final int ERROR_TIMEOUT = 1001;
  7. public static final int ERROR_SERVER_EXCEPTION = 1002;
  8. public static final int ERROR_EMPTY_OBJ = 1011;
  9. public static final int ERROR_ALREADY_REGISTER = 100001; // 已经注册过
  10. public static final int ERROR_LOGIN_EXPIRED = 100002; // 登录cookie超时,需要重新登录
  11. public static final SparseArray<String> ERRORS = new SparseArray<>();
  12. static {
  13. ERRORS.append(ERROR_UNKNOWN, "未知错误");
  14. ERRORS.append(ERROR_SUCCESS, "请求成功");
  15. ERRORS.append(ERROR_NETWORK, "网络错误");
  16. ERRORS.append(ERROR_TIMEOUT, "连接超时");
  17. ERRORS.append(ERROR_SERVER_EXCEPTION, "服务器异常");
  18. ERRORS.append(ERROR_ALREADY_REGISTER, "您的手机号已经注册过i云保帐号");
  19. ERRORS.append(ERROR_LOGIN_EXPIRED, "登录超时,需要重新登录");
  20. ERRORS.append(ERROR_EMPTY_OBJ, "返回对象为空!");
  21. }
  22. }

生命周期绑定

有时我们关闭一个页面时,希望该页面上正在进行以及准备开始进行的请求能够及时关闭、取消掉。以免造成内存溢出或空指针异常等问题。此时就需要将请求与页面的生命周期相关联。因为Retrofit和RxJava2集成,由RxJava2控制上下游的时间分发,所以处理RxJava2的生命周期问题就是处理Retrofit请求的声明周期问题。可以看到在上面的”依赖配置“段落中导入了三个rxlifiecycle相关的依赖,其中rxliftcycle-components包含我们将要使用到的RxAppCompatActivity,而他有依赖另外两个依赖,可以查看RxAppCompatActivity的源码验证:

  1. //RxAppCompatActivity.java
  2. import com.trello.rxlifecycle2.LifecycleProvider;
  3. import com.trello.rxlifecycle2.LifecycleTransformer;
  4. //来自基础包rxlifecycle
  5. import com.trello.rxlifecycle2.RxLifecycle;
  6. //来自android包rxlifecycle-android
  7. import com.trello.rxlifecycle2.android.ActivityEvent;
  8. //来自android包rxlifecycle-android
  9. import com.trello.rxlifecycle2.android.RxLifecycleAndroid;
  10. import io.reactivex.Observable;
  11. import io.reactivex.subjects.BehaviorSubject;
  12. public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {
  13. ......
  14. }

下面开始声明周期相关的Demo,演示一下未绑定页面生命周期导致内存溢出的问题,假设有一个Activity中有一个operator每隔1秒发送一个事件:

  1. public class TestMemLeakActivity extends Activity {
  2. private String TAG = "TestMemLeak";
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.rx_act_test_leak);
  7. Observable.interval(1000l, TimeUnit.MILLISECONDS)
  8. .subscribeOn(Schedulers.computation())
  9. .observeOn(AndroidSchedulers.mainThread())
  10. .subscribe(new Observer<Long>() {
  11. @Override
  12. public void onSubscribe(Disposable d) {
  13. }
  14. @Override
  15. public void onNext(Long aLong) {
  16. Log.d(TAG,aLong + "");
  17. }
  18. @Override
  19. public void onError(Throwable e) {
  20. Log.d(TAG,e.getMessage());
  21. }
  22. @Override
  23. public void onComplete() {
  24. Log.d(TAG,"onComplete");
  25. }
  26. });
  27. }
  28. @Override
  29. protected void onDestroy() {
  30. super.onDestroy();
  31. Log.d(TAG,"onDestory------");
  32. }
  33. }
  34. >>>输出:
  35. 04-29 19:38:00.102 18964-18964/com.ebm.rxjava D/TestMemLeak: 0
  36. 04-29 19:38:01.101 18964-18964/com.ebm.rxjava D/TestMemLeak: 1
  37. 04-29 19:38:02.101 18964-18964/com.ebm.rxjava D/TestMemLeak: 2
  38. 04-29 19:38:03.102 18964-18964/com.ebm.rxjava D/TestMemLeak: 3
  39. 04-29 19:38:04.102 18964-18964/com.ebm.rxjava D/TestMemLeak: 4
  40. 04-29 19:38:05.102 18964-18964/com.ebm.rxjava D/TestMemLeak: 5
  41. 04-29 19:38:05.110 18964-18964/com.ebm.rxjava D/TestMemLeak: onDestory------
  42. 04-29 19:38:06.105 18964-18964/com.ebm.rxjava D/TestMemLeak: 6
  43. 04-29 19:38:07.102 18964-18964/com.ebm.rxjava D/TestMemLeak: 7
  44. 04-29 19:38:08.102 18964-18964/com.ebm.rxjava D/TestMemLeak: 8
  45. 04-29 19:38:09.102 18964-18964/com.ebm.rxjava D/TestMemLeak: 9

从Log可以看出,TestMemLeakActivity关闭调用onDestory()之后,事件没有随着界面关闭而停止发送,这样会导致Activity无法回收,进而导致内存泄露。下面使用RxAppCompatActivity进行将RxJava绑定到Activity的声明周期。

  1. //1.继承自RxAppCompatActivity
  2. public class TestMemLeakActivity extends RxAppCompatActivity {
  3. private String TAG = "TestMemLeak";
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.rx_act_test_leak);
  8. Observable.interval(1000l, TimeUnit.MILLISECONDS)
  9. .subscribeOn(Schedulers.computation())
  10. .observeOn(AndroidSchedulers.mainThread())
  11. //2.绑定声明周期
  12. .compose(this.<Long>bindToLifecycle())
  13. .subscribe(new Observer<Long>() {
  14. @Override
  15. public void onSubscribe(Disposable d) {
  16. }
  17. @Override
  18. public void onNext(Long aLong) {
  19. Log.d(TAG,aLong + "");
  20. }
  21. @Override
  22. public void onError(Throwable e) {
  23. Log.d(TAG,e.getMessage());
  24. }
  25. @Override
  26. public void onComplete() {
  27. Log.d(TAG,"onComplete");
  28. }
  29. });
  30. }
  31. @Override
  32. protected void onDestroy() {
  33. super.onDestroy();
  34. Log.d(TAG,"onDestory------");
  35. }
  36. }
  37. >>>输出:
  38. 04-29 19:41:41.254 20080-20080/com.ebm.rxjava D/TestMemLeak: 0
  39. 04-29 19:41:42.254 20080-20080/com.ebm.rxjava D/TestMemLeak: 1
  40. 04-29 19:41:43.254 20080-20080/com.ebm.rxjava D/TestMemLeak: 2
  41. 04-29 19:41:44.253 20080-20080/com.ebm.rxjava D/TestMemLeak: 3
  42. 04-29 19:41:44.762 20080-20080/com.ebm.rxjava D/TestMemLeak: onComplete
  43. 04-29 19:41:44.762 20080-20080/com.ebm.rxjava D/TestMemLeak: onDestory------

从上面的Log可以看出,界面关闭之前先发送了onComplete事件,关闭了事件流的发送。

Retrofit的优点的更多相关文章

  1. 基于Retrofit+RxJava的Android分层网络请求框架

    目前已经有不少Android客户端在使用Retrofit+RxJava实现网络请求了,相比于xUtils,Volley等网络访问框架,其具有网络访问效率高(基于OkHttp).内存占用少.代码量小以及 ...

  2. Retrofit源码设计模式解析(下)

    本文将接着<Retrofit源码设计模式解析(上)>,继续分享以下设计模式在Retrofit中的应用: 适配器模式 策略模式 观察者模式 单例模式 原型模式 享元模式 一.适配器模式 在上 ...

  3. Retrofit分析-漂亮的解耦套路

    没耐心自己分析源码的同学,还可以参考Stay录制的视频版 Retrofit分析-漂亮的解耦套路(视频版) 万万没想到Retrofit会这么火,在没看源码之前,我简单的认为是因为它跟OkHttp同出一源 ...

  4. 浅谈 RxAndroid + Retrofit + Databinding

    http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0131/3930.html 最近 RxAndroid .MVP.MVVM 一直是 And ...

  5. Android常用网络请求框架Volley Retrofit (okHttp)

    Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient.在 Android 5.0 的时候 Google 就不推荐使用 HttpClient ...

  6. Retrofit/OkHttp API接口加固技术实践(下)

    作者/Tamic http://blog.csdn.net/sk719887916/article/details/65448628 imageMogr2/auto-orient/strip%7Cim ...

  7. MVP+Dagger2+Rxjava+Retrofit+GreenDao 开发的小应用,包括新闻、图片、视频3个大模块,代码封装良好

    练习MVP架构开发的App,算是对自己学过的知识做一个总结,做了有一段时间,界面还算挺多的.代码量还是有的,里面做了大量封装,总体代码整理得非常干净,这个我已经尽力整理了. 不管是文件(java.xm ...

  8. 「2020 新手必备 」极速入门 Retrofit + OkHttp 网络框架到实战,这一篇就够了!

    老生常谈 什么是 Retrofit ? Retrofit 早已不是什么新技术了,想必看到这篇博客的大家都早已熟知,这里就不啰嗦了,简单介绍下: Retrofit 是一个针对 Java 和 Androi ...

  9. 【知识必备】RxJava+Retrofit二次封装最佳结合体验,打造懒人封装框架~

    一.写在前面 相信各位看官对retrofit和rxjava已经耳熟能详了,最近一直在学习retrofit+rxjava的各种封装姿势,也结合自己的理解,一步一步的做起来. 骚年,如果你还没有掌握ret ...

随机推荐

  1. Dynamics CRM中的操作(action)是否是一个事务(transaction)?

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复168或者20151104可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! 以前的博文 微软Dynamics ...

  2. RSA加密算法破解及原理

    - RSA算法原理 - - 加密与解密 在RSA中,Bob想给Alice发一个消息X,Alice公钥为(e,n),私钥为(n,d). 加密和解密的过程如下: - RSA暴力破解 RSA暴力破解,简单理 ...

  3. Android App自动更新解决方案(DownloadManager)

    一开始,我们先向服务器请求数据获取版本 public ObservableField<VersionBean> appVersion = new ObservableField<&g ...

  4. ucoreOS_lab6 实验报告

    所有的实验报告将会在 Github 同步更新,更多内容请移步至Github:https://github.com/AngelKitty/review_the_national_post-graduat ...

  5. SRDC - ORA-30013: Checklist of Evidence to Supply (Doc ID 1682701.1)

    Action Plan 1. Execute srdc_db_undo_ora-30013.sql as sysdba and provide the spool output --srdc_db_u ...

  6. Nginx的负载均衡算法、lvs的负载均衡算法

    NGINX: 官方默认的算法: RR:轮询 weight:权重 ip_hash:配置此项后weight项失效 第三方模块: fair:根据后端服务器的繁忙程度 url_hash:如果客户端访问的url ...

  7. [PHP] PHP PDO与mysql的连接单例防止超时情况处理

    这个数据库类主要处理了单例模式下创建数据库对象时,如果有两次较长时间的间隔去执行sql操作,再次处理会出现连接失败的问题,利用一个cache数组存放pdo对象与时间戳,把两次执行之间的时间进行了比较, ...

  8. Windows下的命令行终端 cmder

    Windows下有很多比系统自带的cmd或者PowerShell好用的命令行工具,cmder是最为推荐的一款. 1.从cmder官网直接下载,一般下载full版本,下载完成后解压文件到自己指定的目录, ...

  9. 关于linux shell的一点知识

    $ . a.sh 接受脚本中环境变量,如声明  b=2 &!进程号 内置环境变量

  10. python获取某路径下,某种特定类型的文件名称,os.walk(路径)生成器;os.listdir(路径),os.path.splitext(名称),os.path.join(路径,名称),os.path.isdir(路径\名称)

    #获取某文件夹下制定类型文件# import os# def filep(fp):# l=[]# a=os.walk(fp) #生成器# for nowp,sonp,oth in a: #当前目录,子 ...