Retrofit2---网络交互的艺术
Posted 逆水当行舟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Retrofit2---网络交互的艺术相关的知识,希望对你有一定的参考价值。
Retrofit是啥
A type-safe HTTP client for android and Java
翻译:Android和Java使用类型安全的Http客户端
Retrofit的前世今生
Http客户端用来做网络访问,网络访问,对绝大多数应用来说是一个基础功能
我们来简单回顾下网络访问框架的发展史:
1. HttpUrlConnection和HttpClient。Android2.1时代,还没有什么框架流行,请求网络都用这个。HttpUrlConnection刚出来的时候Bug巨多,比如说—对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。后面一直有人在维护,在Android 2.3版本的时候,谷歌加入了更加透明化的响应压缩。 在Android 4.0版本中,又添加了一些响应的缓存机制。HttpClient是Apache的,出来的时候比较稳定,但是Android官方对它一直都没怎么维护,甚至从Android5.1版本开始已经把它从SDK移除了,如果还在使用的同学需要自己去手动导入Apache的包。
2. android-async-http。随后又出现了async-http,它在一些反面做了升级,实现了简单的封装,框架雏形。比如:
1. 异步请求能力,匿名回调处理Response
2. 内部使用线程池来处理并发请求,线程重用提高效率
3. Http请求,发生再异步线程
3. Afindl,Xutils。包含网络访问框架,图片加载,数据库,控件绑定框架合成的一系列框架的集合框架。当年他们可是风靡一时,这个很好、很中国。就像小时候玩”学习机”,小霸王其乐无穷时代,4合一、8合一、99合一的赶脚。回过头看,这种框架特别符合中国人的思维方式—极致的使用主义,包含所有,中庸之道。但是兼顾太多,维护框架的人精力又是有限的,很容易就顾此失彼,慢慢的。绑定控件被ButterKnife,Dragger替代;图片加载慢慢的被ImageLoader替代,后来又被Picasso、Glide、Fresco替代;ORM数据库被GreenDao、ORMLite替代;网络–Volley替代;
4. Volley,不可否认Volley是一个出色的网络框架Volley源码解析,拓展性强,设计优雅。
5. OkHttp,Volley虽好但是奈何不住没人维护啊,直接再应用层使用看着臃肿,要自己再封装一次。Volley 默认根据 Android 系统版本使用不同的 Http 传输协议实现.在 Android 3.0 以上 Volley 使用 ApacheHttpStack 作为传输协议, 在2.3 及以下使用 HttpURLConnection 作为传输层协议。注意:3.0以上使用ApacheHttpStack作为传输协议这句话,谷歌从Android5.1开始已经把Apache的东西从SDK中移除了,后面就产生了问题。有很多文章说使用OkHttp+Volley联合开发,最开始看到的时候感觉很迷糊,有了OKHttp干嘛还要加上Volley做网络访问。后面想想应该是这么回事:老项目使用了Volley框架,但是传输协议ApacheHttpStack别人干掉了,所以添加OkHttp框架来做传输就行了,以前的代码不用再修改。
当然OkHttp 是 Square 公司开源的一个 HTTP 网络框架,广受好评。
好了,闲话扯得够多了,步入我们的正题—Retrofit
Retrofit和OkHttp的关系
从字面上理解Retrofit翻译为—改进、改装、对…作样式翻新
同样是Square
公司出品,同样是用作Http Client,Retrofit后于OkHttp,这个翻新的对象明显就是OkHttp了。
当然并不是说就直接覆盖替换了OkHttp,相反OkHttp的功能实现和架构还是很漂亮的。从Retrofit2.0开始内置OkHttp,如果把OkHttp比作一间房子,Retrofit更像是在给房子做装修,让房间变得更好看,没宜居,至于底层的连接、通信、重试这些Retrofit都不关心,交给OkHttp去完成就好。
总之:
- OkHttp专注和服务层Api打交道,提供更稳定可靠的连接
- Retrofit专注和App打交道,提供更友好,易懂易维护的访问方式
为啥说Retrofit写得代码像艺术
多说无益,show me the code
。
例如我们要实现如下展示的功能:
不用Retrofit我们怎么写的代码
步骤:
1. 需要一个服务端Api
接口已准备好:
http://zhuangbi.info/search?q=牛逼
使用调试插件JSONOnlineViewer
,可以直接再IDE里面调试
- 具备常用Get,Post…6种请求方式,配置请求参数
- 返回数据直接是格式化后的Json
- 可以查看请求头信息
2. 根据Api,数据格式编写实体类
使用插件GsonFormat
,直接生成我们需要的实体— Android Studio使用—眼花缭乱的插件使用技巧
3. 配置Gradle文件
我们大概需要,网络访问—使用OkHttp,图片加载—Glide,因为返回的图片类型是gif,所以不考虑Picasso。需要一个V4包的加载组件android.support.v4.widget.SwipeRefreshLayout
,一个V7包的RecyclerView—android.support.v7.widget.RecyclerView
compile 'com.android.support:appcompat-v7:23.2.1'
compile 'com.android.support:support-v4:23.2.1'
compile 'com.android.support:support-v13:23.2.1'
compile 'com.android.support:cardview-v7:23.2.1'
compile 'com.android.support:design:23.2.1'
compile 'com.squareup.okhttp3:okhttp:3.3.1'
compile 'com.jakewharton:butterknife:7.0.1'
compile 'com.squareup.retrofit2:converter-gson:2.0.0' //Gson
compile 'com.github.bumptech.glide:glide:3.7.0'
4.配置HttpClient,访问网络
private void search()
mSwipeRefreshLayout.setRefreshing(true);
Request request = new Request.Builder()
.url("http://zhuangbi.info/search?q=" + getString(R.string.niubility))
.build();
call = mOkHttpClient.newCall(request);
//异步执行
call.enqueue(callBack);
5.在回调方法中,通过Gson之类的工具解析为实体类
Callback callBack = new Callback()
@Override
public void onFailure(Call call, IOException e)
Toast.makeText(App.getContext(), "", Toast.LENGTH_SHORT).show();
mSwipeRefreshLayout.setRefreshing(false);
@Override
public void onResponse(Call call, Response response) throws IOException
//解析json
String resStr = response.body().string();
Gson gson = new Gson();
mDatas = gson.fromJson(resStr, new TypeToken<List<SearchImage>>()
.getType());
getActivity().runOnUiThread(new Runnable()
@Override
public void run()
//更新UI数据
mSwipeRefreshLayout.setRefreshing(false);
mAdapter.setDatas(mDatas);
);
;
- 把实体类里面的数据显示到界面
public class SearchImageAdapter extends RecyclerView.Adapter
private List<SearchImage> mDatas;
public void setDatas(List<SearchImage> datas)
mDatas = datas;
notifyDataSetChanged();
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_grid_search_image, parent, false);
return new SearchImageViewHolder(view);
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
SearchImageViewHolder viewHolder = (SearchImageViewHolder) holder;
SearchImage searchImage = mDatas.get(position);
Glide.with(holder.itemView.getContext())
.load(searchImage.image_url)
.into(viewHolder.mIvShow);
viewHolder.mTvDes.setText(searchImage.description);
@Override
public int getItemCount()
return mDatas == null ? 0 : mDatas.size();
static class SearchImageViewHolder extends RecyclerView.ViewHolder
@Bind(R.id.ivShow)
ImageView mIvShow;
@Bind(R.id.tvDes)
TextView mTvDes;
SearchImageViewHolder(View view)
super(view);
ButterKnife.bind(this, view);
使用Retrofit改写改写
- 配置Gradle
compile 'com.squareup.okhttp3:okhttp:3.3.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
2.配置API访问接口
public interface SearchApi
@GET("search")
Observable<List<SearchImage>> search(@Query("q") String qTitle);
3.返回数据实体,已通过GsonFormat
自动生成了
public class SearchImage
/**
* id : 187
* description : ????????????????????????????
* path : i/2015-07-16-77b07ee973ffd5ab39015b927b04b3c3.jpg
* size : 11007
* width : 220
* height : 94
* created_at : 2015-07-16 16:03:06
* updated_at : 2016-02-26 22:26:41
* user_id : 1
* permitted_at : 2016-02-26 22:26:41
* disk : qiniu
* hotpoint : 101
* channel : null
* upload_id : 167
* image_url : http://zhuangbi.idagou.com/i/2016-02-26-b56183130c20ca2f8b6ec9c6616c1f95.jpg
* file_size : 18.78 KB
*/
private int id;
private String description;
private String path;
private int size;
private int width;
private int height;
private String created_at;
private String updated_at;
private int user_id;
private String permitted_at;
private String disk;
private int hotpoint;
private Object channel;
private int upload_id;
private String image_url;
private String file_size;
...省略
4.步入正题—请求数据
public static SearchApi getSearchApi()
if (sSearchApi == null)
sSearchApi = new Retrofit.Builder()
.client(sOkHttpClient)
.baseUrl("http://zhuangbi.info/")
.addConverterFactory(sGsonConverterFactory)
.addCallAdapterFactory(sRxJavaCallAdapterFactory)
.build()
.create(SearchApi.class);
return sSearchApi;
private void search(String title)
Subscriber<List<SearchImage>> subscriber = new Subscriber<List<SearchImage>>()
@Override
public void onCompleted()
@Override
public void onError(Throwable e)
mSwipeRefreshLayout.setRefreshing(false);
Toast.makeText(App.getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
@Override
public void onNext(List<SearchImage> searchImages)
mSwipeRefreshLayout.setRefreshing(false);
//显示数据
mAdapter.setDatas(searchImages);
;
mSubscription = NetWork.getSearchApi() //获取SearchApi 具备网络通信能力
.search(title) //访问特定Api接口
.subscribeOn(Schedulers.io())//指定在非UI线程访问,执行(被观察)事件
.observeOn(AndroidSchedulers.mainThread())//指定在UI线程执行观察者(回调)结果
.subscribe(subscriber);//观察者(回调)执行
OK,以上就是Retrofit的简单使用。
代码下载:https://github.com/zhouruikevin/RxJavaSamples-master
以上是关于Retrofit2---网络交互的艺术的主要内容,如果未能解决你的问题,请参考以下文章
Retrofit2.0+RxJava+RxAndroid——强强联合的网络请求框架