retrofit 的封装

前言

上一篇文章的链接
http://blog.csdn.net/qq_26296197/article/details/78011188

1 上一篇文章讲到Retrofit可以发起同步和异步请求,在这里贴下代码

//发送网络请求(异步)call.enqueue(new Callback<Translation>() {//请求成功时回调@Overridepublic void onResponse(Call<Translation> call, Response<Translation> response) {//请求处理,输出结果response.body().show();}//请求失败时候的回调@Overridepublic void onFailure(Call<Translation> call, Throwable throwable) {System.out.println("连接失败");}});// 发送网络请求(同步)
Response<Reception> response = call.execute();
// 对返回数据进行处理response.body().show();

上一篇文章知道了Retrofit的基本请求方法,但是没有加入注释,这对初学者可能存在一些困惑,在这里贴上带有注释的代码,熟悉Retrofit基本用法的朋友可以温故而知新,同时新手学习起来也没有那么吃力。

public class GetRequest extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);request();// 使用Retrofit封装的方法}public void request() {//步骤4:创建Retrofit对象Retrofit retrofit = new Retrofit.Builder().baseUrl("http://fy.iciba.com/") // 设置 网络请求 Url.addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖).build();// 步骤5:创建 网络请求接口 的实例GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);//对 发送请求 进行封装Call<Translation> call = request.getCall();//步骤6:发送网络请求(异步)call.enqueue(new Callback<Translation>() {//请求成功时回调@Overridepublic void onResponse(Call<Translation> call, Response<Translation> response) {// 步骤7:处理返回的数据结果response.body().show();}//请求失败时回调@Overridepublic void onFailure(Call<Translation> call, Throwable throwable) {System.out.println("连接失败");}});}
}

Retrofit扩展使用,加入rxjava
首先需要添加依赖:

    compile 'io.reactivex.rxjava2:rxjava:2.1.3'compile 'com.squareup.retrofit2:retrofit:2.3.0'compile 'com.squareup.retrofit2:converter-gson:2.3.0'compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

基本的写法 :

Retrofit retrofit = new Retrofit.Builder().baseUrl(""http://fanyi.youdao.com/"").addConverterFactory(GsonConverterFactory.create()) // 支持Gson解析.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava.build();

最基本的RxJava+Retrofit

添加权限

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

1.创建Service类
因为要结合使用RxJava,所以返回值就不在是一个Call了,而是一个Observable。

public interface ApiService {@GET("top250")Observable<Movie> getTopMovie(@Query("start") int start, @Query("count") int count);
}

2.创建Retrofit请求过程

 String baseUrl = "https://api.douban.com/v2/movie/";Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl) .addConverterFactory(ScalarsConverterFactory.create())//请求结果转换为基本类型.addConverterFactory(GsonConverterFactory.create())//请求的结果转为实体类.addCallAdapterFactory(RxJava2CallAdapterFactory.create())  //适配RxJava2.0, RxJava1.x则为RxJavaCallAdapterFactory.create().build();apiService = retrofit.create(ApiService.class);

3.Activity发出请求(RxJava订阅)及处理数据
注意:RxJava2.0开始subscribe的对象不能是Subscriber,只能是Observer和Consumer,为了处理完整的过程我们这里选择Observer。 onSubscribe等同于onStart。

apiService.getTopMovie(0, 10).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Movie>() {@Overridepublic void onSubscribe(Disposable d) {Log.d(TAG, "onSubscribe: ");}@Overridepublic void onNext(Movie movie) {Log.d(TAG, "onNext: " + movie.getTitle());List<Subjects> list = movie.getSubjects();for (Subjects sub : list) {Log.d(TAG, "onNext: " + sub.getId() + "," + sub.getYear() + "," + sub.getTitle());}}@Overridepublic void onError(Throwable e) {Log.e(TAG, "onError: " + e.getMessage());}@Overridepublic void onComplete() {Log.d(TAG, "onComplete: Over!");}});

4.运行结果

09-06 14:25:09.151 30008-30008/eee.rxjavaretrofit D/MainActivity: onSubscribe:
09-06 14:25:11.308 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 豆瓣电影Top250
09-06 14:25:11.308 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1292052,1994,肖申克的救赎
09-06 14:25:11.308 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1291546,1993,霸王别姬
09-06 14:25:11.308 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1295644,1994,这个杀手不太冷
09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1292720,1994,阿甘正传
09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1292063,1997,美丽人生
09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1291561,2001,千与千寻
09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1295124,1993,辛德勒的名单
09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1292722,1997,泰坦尼克号
09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 3541415,2010,盗梦空间
09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 2131459,2008,机器人总动员
09-06 14:25:11.311 30008-30008/eee.rxjavaretrofit D/MainActivity: onComplete: Over!

这样就完成了最基本的RxJava+Retrofit,结果也与预期一致。
但是这样显然不能让我们去优雅的使用。毕竟优雅的复用已写过的代码才是我们的追求。

因此我们需要进一步对刚才的代码进行封装。

基本的封装RxJava+Retrofit

1.封装Retrofit请求过程
在之前的代码的基础上,创建Api.java用于封装Retrofit,代码如下:

public class Api {public static String baseUrl = "https://api.douban.com/v2/movie/";public static ApiService apiService;//单例public static ApiService getApiService() {if (apiService == null) {synchronized (Api.class) {if (apiService == null) {new Api();}}}return apiService;}private Api() {Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(GsonConverterFactory.create())//请求的结果转为实体类//适配RxJava2.0,RxJava1.x则为RxJavaCallAdapterFactory.create().addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();apiService = retrofit.create(ApiService.class);}}

2.封装线程管理和订阅
在使用RxJava的过程中,每次都重复写线程管理和订阅代码也是一件繁琐的事情。
创建ApiMethods用于封装线程管理和订阅的过程及调用请求。如下:

public class ApiMethods {/*** 封装线程管理和订阅的过程*/public static void ApiSubscribe(Observable observable, Observer observer) {observable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(observer);}/*** 用于获取豆瓣电影Top250的数据** @param observer 由调用者传过来的观察者对象* @param start    起始位置* @param count    获取长度*/public static void getTopMovie(Observer<Movie> observer, int start, int count) {ApiSubscribe(Api.getApiService().getTopMovie(start, count), observer);}
}

3.Activity中调用及处理数据

 Observer<Movie> observer = new Observer<Movie>() {@Overridepublic void onSubscribe(Disposable d) {Log.d(TAG, "onSubscribe: ");}@Overridepublic void onNext(Movie movie) {Log.d(TAG, "onNext: " + movie.getTitle());List<Subjects> list = movie.getSubjects();for (Subjects sub : list) {Log.d(TAG, "onNext: " + sub.getId() + "," + sub.getYear() + "," + sub.getTitle());}}@Overridepublic void onError(Throwable e) {Log.e(TAG, "onError: " + e.getMessage());}@Overridepublic void onComplete() {Log.d(TAG, "onComplete: Over!");}};ApiMethods.getTopMovie(observer, 0, 10);

4.测试结果

09-06 15:14:01.413 16819-16819/eee.rxjavaretrofit D/MainActivity: onSubscribe:
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 豆瓣电影Top250
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1292052,1994,肖申克的救赎
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1291546,1993,霸王别姬
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1295644,1994,这个杀手不太冷
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1292720,1994,阿甘正传
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1292063,1997,美丽人生
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1291561,2001,千与千寻
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1295124,1993,辛德勒的名单
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1292722,1997,泰坦尼克号
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 3541415,2010,盗梦空间
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 2131459,2008,机器人总动员
09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onComplete: Over!

经过两次封装,如果有新的Api接口我们只需要在ApiService类中增加对应的接口方法,然后在ApiMethods类中写对应的请求方法即可。与基本的RxJava+Retrofit相比,在额外代码量和易用性上都明显占优。

进一步封装RxJava+Retrofit

看完上一步,你还是肯定还是会觉得,在Activity每次处理订阅返回的数据的时候都要实例化一个Observer对象,然后重写onSubscribe,onNext,onError,onComplete四个方法。虽然Android Studio一键就能补全代码,我们只用简单处理一下就ok了。但是那么多代码堆在那里还是让人不爽的。
因此我们进一步针对Observer进行封装。
针对重写方法的封装最好的方法就是使用接口+implements/继承的方式实现。
仔细分析会发现,其实除了onNext涉及数据处理,其余三个方法都可以进行模板化处理,比如显示一个Toast,输出错误信息等;当然如果你的业务需要,也可以按照onNext特别处理。
在之前代码的基础上。

1.新建监听接口
使用通配泛型,适用于所有类型的数据。

public interface ObserverOnNextListener<T> {void onNext(T t);
}

2.重写Observer

public class MyObserver<T> implements Observer<T> {private static final String TAG = "MyObserver";private ObserverOnNextListener listener;private Context context;public MyObserver(Context context, ObserverOnNextListener listener) {this.listener = listener;this.context = context;}@Overridepublic void onSubscribe(Disposable d) {Log.d(TAG, "onSubscribe: ");//添加业务处理}@Overridepublic void onNext(T t) {listener.onNext(t);}@Overridepublic void onError(Throwable e) {Log.e(TAG, "onError: ", e);//添加业务处理}@Overridepublic void onComplete() {Log.d(TAG, "onComplete: ");//添加业务处理}
}

3.Activity中使用

 ObserverOnNextListener<Movie> listener = new ObserverOnNextListener<Movie>() {@Overridepublic void onNext(Movie movie) {Log.d(TAG, "onNext: " + movie.getTitle());List<Subjects> list = movie.getSubjects();for (Subjects sub : list) {Log.d(TAG, "onNext: " + sub.getId() + "," + sub.getYear() + "," + sub.getTitle());}}};ApiMethods.getTopMovie(new MyObserver<Movie>(this, listener), 0, 10);

4.测试结果

09-06 16:01:59.918 3487-3487/eee.rxjavaretrofit D/MyObserver: onSubscribe:
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 豆瓣电影Top250
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1292052,1994,肖申克的救赎
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1291546,1993,霸王别姬
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1295644,1994,这个杀手不太冷
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1292720,1994,阿甘正传
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1292063,1997,美丽人生
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1291561,2001,千与千寻
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1295124,1993,辛德勒的名单
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1292722,1997,泰坦尼克号
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 3541415,2010,盗梦空间
09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 2131459,2008,机器人总动员
09-06 16:02:00.718 3487-3487/eee.rxjavaretrofit D/MyObserver: onComplete: 

优雅的封装RxJava+Retrofit

上面的代码可谓是封装的彻底了,但是还不够优雅。
如何优雅?
网络请求一般都是耗时的,我们需要在进行网络请求的时候有一个进度框,增加用户体验。
根据上一步,我们只需要将进度框show在onSubscribe中,然后在onError/onComplete里cancel掉就行了。如果用户取消关闭了进度框,那么也随之取消了当前的Http请求。

1.编写ProgressDialog类代码
Handler接收两个消息来控制显示Dialog还是关闭Dialog。

public class ProgressDialogHandler extends Handler {public static final int SHOW_PROGRESS_DIALOG = 1;public static final int DISMISS_PROGRESS_DIALOG = 2;private ProgressDialog pd;private Context context;private boolean cancelable;private ProgressCancelListener mProgressCancelListener;public ProgressDialogHandler(Context context, ProgressCancelListenermProgressCancelListener, boolean cancelable) {super();this.context = context;this.mProgressCancelListener = mProgressCancelListener;this.cancelable = cancelable;}private void initProgressDialog() {if (pd == null) {pd = new ProgressDialog(context);pd.setCancelable(cancelable);if (cancelable) {pd.setOnCancelListener(new DialogInterface.OnCancelListener() {@Overridepublic void onCancel(DialogInterface dialogInterface) {mProgressCancelListener.onCancelProgress();}});}if (!pd.isShowing()) {pd.show();}}}private void dismissProgressDialog() {if (pd != null) {pd.dismiss();pd = null;}}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case SHOW_PROGRESS_DIALOG:initProgressDialog();break;case DISMISS_PROGRESS_DIALOG:dismissProgressDialog();break;}}
}

此处安全按照参考文章来写的,当然你也可以直接ProgressDialog dialog = new ProgressDialog(context);

2.编写监听取消的接口类

public interface ProgressCancelListener {void onCancelProgress();
}

3.在MyObserver中添加ProgressDialog
将上面ProgressDialog在Observer中初始化,并在相应的位置进行显示和隐藏。

public class ProgressObserver<T> implements Observer<T>, ProgressCancelListener {private static final String TAG = "ProgressObserver";private ObserverOnNextListener listener;private ProgressDialogHandler mProgressDialogHandler;private Context context;private Disposable d;public ProgressObserver(Context context, ObserverOnNextListener listener) {this.listener = listener;this.context = context;mProgressDialogHandler = new ProgressDialogHandler(context, this, true);}private void showProgressDialog() {if (mProgressDialogHandler != null) {mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();}}private void dismissProgressDialog() {if (mProgressDialogHandler != null) {mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget();mProgressDialogHandler = null;}}@Overridepublic void onSubscribe(Disposable d) {this.d = d;showProgressDialog();}@Overridepublic void onNext(T t) {listener.onNext(t);}@Overridepublic void onError(Throwable e) {dismissProgressDialog();Log.e(TAG, "onError: ", e);}@Overridepublic void onComplete() {dismissProgressDialog();Log.d(TAG, "onComplete: ");}@Overridepublic void onCancelProgress() {//如果处于订阅状态,则取消订阅if (!d.isDisposed()) {d.dispose();}}
}

5.Activity中使用

 ObserverOnNextListener<Movie> listener = new ObserverOnNextListener<Movie>() {@Overridepublic void onNext(Movie movie) {Log.d(TAG, "onNext: " + movie.getTitle());List<Subjects> list = movie.getSubjects();for (Subjects sub : list) {Log.d(TAG, "onNext: " + sub.getId() + "," + sub.getYear() + "," + sub.getTitle());}}};ApiMethods.getTopMovie(new ProgressObserver<Movie>(this, listener), 0, 10);

6.测试结果

09-06 16:32:05.135 6823-6823/eee.rxjavaretrofit D/ProgressObserver: onSubscribe:
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 豆瓣电影Top250
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1292052,1994,肖申克的救赎
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1291546,1993,霸王别姬
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1295644,1994,这个杀手不太冷
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1292720,1994,阿甘正传
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1292063,1997,美丽人生
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1291561,2001,千与千寻
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1295124,1993,辛德勒的名单
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1292722,1997,泰坦尼克号
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 3541415,2010,盗梦空间
09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 2131459,2008,机器人总动员
09-06 16:32:05.992 6823-6823/eee.rxjavaretrofit D/ProgressObserver: onComplete: 

优化Retrofit,设置缓存,超时策略

使用OkHttpClient对Retrofit设置设置缓存,超时策略。

首先先添加依赖

 compile 'com.squareup.okhttp3:okhttp:3.9.0'compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'

okhttp3:logging-interceptor是为了配置缓存策略,必须跟okhttp同一版本号,否则会报错:Failed resolution of: Lokhttp3/internal/Platform

public class ApiStrategy {public static String baseUrl = "https://api.douban.com/v2/movie/";//读超时长,单位:毫秒public static final int READ_TIME_OUT = 7676;//连接时长,单位:毫秒public static final int CONNECT_TIME_OUT = 7676;public static ApiService apiService;public static ApiService getApiService() {if (apiService == null) {synchronized (Api.class) {if (apiService == null) {new ApiStrategy();}}}return apiService;}private ApiStrategy() {HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);//缓存File cacheFile = new File(MyApplication.getContext().getCacheDir(), "cache");Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb//增加头部信息Interceptor headerInterceptor = new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request build = chain.request().newBuilder()//.addHeader("Content-Type", "application/json")//设置允许请求json数据.build();return chain.proceed(build);}};//创建一个OkHttpClient并设置超时时间OkHttpClient client = new OkHttpClient.Builder().readTimeout(READ_TIME_OUT, TimeUnit.MILLISECONDS).connectTimeout(CONNECT_TIME_OUT, TimeUnit.MILLISECONDS).addInterceptor(mRewriteCacheControlInterceptor).addNetworkInterceptor(mRewriteCacheControlInterceptor).addInterceptor(headerInterceptor).addInterceptor(logInterceptor).cache(cache).build();Retrofit retrofit = new Retrofit.Builder().client(client).baseUrl(baseUrl).addConverterFactory(GsonConverterFactory.create())//请求的结果转为实体类//适配RxJava2.0,RxJava1.x则为RxJavaCallAdapterFactory.create().addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();apiService = retrofit.create(ApiService.class);}/*** 设缓存有效期为两天*/private static final long CACHE_STALE_SEC = 60 * 60 * 24 * 2;/*** 云端响应头拦截器,用来配置缓存策略* Dangerous interceptor that rewrites the server's cache-control header.*/private final Interceptor mRewriteCacheControlInterceptor = new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();String cacheControl = request.cacheControl().toString();if (!NetWorkUtils.isNetConnected(MyApplication.getContext())) {request = request.newBuilder().cacheControl(TextUtils.isEmpty(cacheControl) ? CacheControl.FORCE_NETWORK : CacheControl.FORCE_CACHE).build();}Response originalResponse = chain.proceed(request);if (NetWorkUtils.isNetConnected(MyApplication.getContext())) {return originalResponse.newBuilder().header("Cache-Control", cacheControl).removeHeader("Pragma").build();} else {return originalResponse.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" +CACHE_STALE_SEC).removeHeader("Pragma").build();}}};
}

总结

目前为止,就封装完毕了。
本文章demo http://download.csdn.net/download/qq_26296197/10265153
这个是结合MVP的封装 http://download.csdn.net/download/qq_26296197/10262210

retrofit框架学习(二)----retrofit封装相关推荐

  1. PyTorch框架学习二——基本数据结构(张量)

    PyTorch框架学习二--基本数据结构(张量) 一.什么是张量? 二.Tensor与Variable(PyTorch中) 1.Variable 2.Tensor 三.Tensor的创建 1.直接创建 ...

  2. PyTorch框架学习二十——模型微调(Finetune)

    PyTorch框架学习二十--模型微调(Finetune) 一.Transfer Learning:迁移学习 二.Model Finetune:模型的迁移学习 三.看个例子:用ResNet18预训练模 ...

  3. Struts2框架学习(二) Action

    Struts2框架学习(二) Action Struts2框架中的Action类是一个单独的javabean对象.不像Struts1中还要去继承HttpServlet,耦合度减小了. 1,流程 拦截器 ...

  4. 《SpringBoot框架学习二之HTTP协议》

    <SpringBoot框架学习二之HTTP协议> 文章目录 <SpringBoot框架学习二之HTTP协议> 一.HTTP介绍 (1)概述 (2)HTTP版本协议 1.HTTP ...

  5. Retrofit详解(二)(Retrofit核心流程)

    上一章已经介绍了Retrofit创建过程,这章介绍Retrofit Api Service创建与访问过程. Retrofit 相比Volley等网络框架一个最大区别就是它只需要声明接口,就可以访问网络 ...

  6. retrofit框架学习(一)----基本用法

    首先公布下我学习retrofit的思维导图 如果大家有需要这个思维导图,可在下面留言,我看到后会分享给你. 前言 什么是retrofit? 官方的回答是: A type-safe HTTP clien ...

  7. Retrofit框架(二)

    一.GET请求列表数据展示 添加依赖 dependencies {compile 'com.squareup.picasso:picasso:2.5.2'compile 'com.squareup.r ...

  8. Netty 框架学习(二):DelimiterBasedFrameDecoder和FixedLengthFrameDecoder

    文章目录 一.DelimiterBasedFrameDecoder 服务端 1.EchoServer 2.EchoServerChannelHandler 3.EchoServerHandler 客户 ...

  9. Netty 框架学习(二):Netty粘包和拆包

    文章目录 一.什么是粘包和拆包 二.粘包和拆包示例代码 1.TimeServerHandler 2.TimeClientHandler 三.使用Netty解决粘包和拆包 1.TimeServerHan ...

最新文章

  1. matlab实例 pdf,matlab65实例教程(含语句注释).pdf
  2. Asp.net,C# 加密解密字符串
  3. 《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进
  4. 西门子s7-200解密软件下载_西门子S7200仿真软件如何使用?
  5. [zz from newsmth] 王大牛的Memory Model reading list
  6. php中函数前加符号的作用分解
  7. 紫为云 2020春招开启!算法职位20K-50K!
  8. 【LeetCode】剑指 Offer 45. 把数组排成最小的数
  9. scala的字符串的方法(五)
  10. 【渝粤教育】国家开放大学2018年秋季 7389-22T劳动与社会保障法 参考试题
  11. MySQL 亿级数据分页的优化
  12. 软件体系结构六大质量属性-浅析淘宝网
  13. JavaSE基础——注解
  14. java语言程序设计 第八版 基础篇_Java语言程序设计基础篇(第八版)编程8.7答案
  15. 《数学建模与数学实验》第5版 线性规划 习题3.4
  16. 直播app源码的搭建,仍有许多问题等待我们去解决
  17. python与或非运算规则_Python逻辑运算符之与或非
  18. 如何将ppt压缩到最小?
  19. 【pytorch yolov5 模型优化和超参数自动调整】
  20. #NAME?_#NAME?

热门文章

  1. Hadoop(六)搭建分布式HBase集群
  2. 发动机性能测试软件,发动机的性能测试方法
  3. 二叉树构造c语言实现,递归创建二叉树c语言实现+详细解释
  4. matlab 量化 策略,【策略分享】Matlab量化交易策略源码分享
  5. mysql存储日期 jsp_JSP+MySql的时间处理
  6. JAVA学习-JAVA实现一元二次方程求解
  7. OpenShift 4 之获取OpenShif的最新开发进度
  8. java转js_java对象转js对象
  9. mysql编译安装原理_MySQL编译安装全过程
  10. 关于ssm框架的整理(三) 2021-05-11