在项目开发过程中,我们或多或少的使用过很多网络请求库。基本点的就是原生的http请求框架,好比HttpClient以及HttpUrlConnection等,略懂android开发的估计无人不知android-async-http或者volley啥的,再往上走,你可能会接触okhttp等。今天我们将来介绍一个新的http请求框架,隆重推荐Retrofit

Retrofit是何方神圣

retrofit是Square公司出品的,为android和java提供一个类型安全的Http网络请求库,这里是官网地址。

Retrofit的优点

使用注解来描述http请求
1.URL参数的替换和query参数的支持
2.对象转化为请求体(如:JSON,protocol buffers等)
3.多重请求体和文件上传
以上都是官网描述

使用流程

  • 权限
<uses-permission android:name="android.permission.INTERNET" />

这个没什么好说的,没有网络权限什么都做不了

  • 导包
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
compile 'io.reactivex:rxjava:1.1.2'
compile 'io.reactivex:rxandroid:1.1.0'

这里几个库的含义是:我们使用retrofit2.0去进行网络请求操作,同时我们使用gson去进行数据解析,并且结合rxjava去进行相应的代码编写

  • 基本配置
new Retrofit.Builder().addCallAdapterFactory(RxJavaCallAdapterFactory.create()).addConverterFactory(GsonConverterFactory.create()).client(okhttpBuilder.build()).baseUrl(baseUrl).build();

这段就是使用RxJava,利用gson做解析(这边解析器可以设置注入Jackson之类的,甚至可以自定义),http引擎框架是okhttp

  • API说明

Retrofit需要通过注解请求方法以及请求参数来表明应该如何去进行一个Http请求,目前内置了5种注解方式GET、POST、PUT、DELETE以及HEAD。同时资源的相对URL要在注解中明确的指出。比如请求方法

@Get("/a/b")
  • api使用

配置都OK之后,现在就开始写URL接口了。

案例1

假设有这么一个请求

看看这个GET请求,有header也有urlParam。我们可以使用@Header对header部分进行描述,后面使用@Query去添加每一个跟随urlParam

@GET("weatherservice/cityname")
Observable<WeatherModel> getWeatherModels(@Header("apikey") String apikey, @Query("cityname") String cityname);

同时如果你觉得一个一个的@Query写的有点烦,Retrofit支持使用@QueryMap,将请求的urlParam都存储在一个Map里

案例2

假设有这么一个请求,来自gankio

看看这个GET请求,跟之前的区别在于,他没有urlParam,但是参数是在url里面,这个时候我们就要采用动态替换url里面的参数的方法,如何做呢?用{}来表明url中的哪部分参数需要替换,相应的参数用@Path来注解同样的字符串

@GET("{type}/{pagenum}/{page}")
public Observable<GankioModel> getGankioModels(@Path("type") String type, @Path("pagenum") int pagenum, @Path("page") int page);

案例3

假设有这么一个请求,

看看这个post请求,与之前的get请求基本类似,只不过请求参数在bodyparams里面了,这个也很简单,通过@Body注解来指定一个方法作为HTTP请求主体

@POST("shipin_kg/shipin_kg")
public Observable<MovieModel> getMovieLists(@Header("apikey") String apikey, @Body MoviePostModel postModel);

案例4

我们在post请求的时候会遇到一种情况就是content-type被指定为某一种格式了
如果服务端告诉你,我们的请求一定要用x-www-form-urlencoded,那么之前说的那种@body就不起作用了,这个时候我们@FormUrlEncoded去表明这个content-type类型,同时要用@Field去处理每一个键值对

@FormUrlEncoded
@POST("product_tool/tool/stagequan")
Observable<ResponseModel> upload(@FieldMap Map<String, String> params);

当然一个个写@Field也很烦,可以直接用@FieldMap去统一用map来处理

案例5

上传文件时候content-type一般都是multipart/form-data,所以这边要加上 @Multipart 注解,同时每个请求部分需要使用 @Part 来注解。这边用七牛上传文件来说明

@Multipart
@POST("http://upload.qiniu.com/")
Call<ResponseBody> uploadImage(@PartMap Map<String, RequestBody> params);

同样使用了@PartMap

来看看RequestBody是怎么创建的

public static RequestBody create(final MediaType contentType, final File file)
public static RequestBody create(MediaType contentType, String content)
public static RequestBody create(final MediaType contentType, final byte[] content) 

找了3个基本方法,它是为了告诉我们,你可以通过contentType以及内容组成任意一个RequestBody对象

RequestBody body = RequestBody.create(MediaType.parse("image/jpeg"), new File(Environment.getExternalStorageDirectory().getPath() + "/PictureTest/saveTemp.jpg"));
params.put("file", body);
params.put("token", RequestBody.create(MediaType.parse("text/plain"), token));
params.put("x:jsonbody", RequestBody.create(MediaType.parse("text/plain"), "{}"));

案例6

刚才看过了上传,现在来看看下载。这边只要借鉴了小凳子提供的下载方法
一般情况下retrofit是将整个文件都读进内存里面的,这样会造成OOM,所以大文件下载需使用@Streaming,同时我们也需要使用动态地址以便于下载不同的文件,这边使用@Url来填充

@Streaming
@GET
Call<ResponseBody> downloadFileWithFixedUrl(@Url String url);

剩下的就是保存文件了

Response<ResponseBody> response=api.downloadFileWithFixedUrl("http://7b1g8u.com1.z0.glb.clouddn.com/app_newkey_release_8_4.apk").execute();
try {if (response != null && response.isSuccessful()) {//文件总长度long fileSize = response.body().contentLength();long fileSizeDownloaded = 0;is = response.body().byteStream();File file = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "app_newkey_release_8_4.apk");if (file.exists()) {file.delete();} else {file.createNewFile();}fos = new FileOutputStream(file);int count = 0;byte[] buffer = new byte[1024];while ((count = is.read(buffer)) != -1) {fos.write(buffer, 0, count);fileSizeDownloaded += count;subscriber.onNext("file download: " + fileSizeDownloaded + " of " + fileSize);}fos.flush();subscriber.onCompleted();} else {subscriber.onError(new Exception("接口请求异常"));}
} catch (Exception e) {subscriber.onError(e);
} finally {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}
}

具体使用

无论你是何种请求方式,在app上面调用的方式基本上都是差不多的,我就拿第一个天气预报的接口加以说明

WeatherApi api = Retrofit2Utils.getInstance(getApplicationContext()).enableCache(true).getRetrofit("http://apis.baidu.com/apistore/").create(WeatherApi.class);
subscription = api.getWeatherModels("a7802d983b3d58ed6e70ed71bb0c7f14", "南京").subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).unsubscribeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<WeatherModel>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onNext(WeatherModel weatherModel) {if (!subscription.isUnsubscribed()) {Log.d("MainActivity", (weatherModel.getRetData().getCity() + " " + weatherModel.getRetData().getDate() + "-" + weatherModel.getRetData().getTime() + " " + weatherModel.getRetData().getWeather()));}}});

我这里使用了缓存操作,这个后面会加以说明。同时使用了Rxjava对请求的线程切换以及对返回结果进行调度

缓存

可以通过这篇文章Retrofit 源码解读之离线缓存策略的实现学习到Retrofit缓存的一些知识,真正实践时我是在这里发现如何使用的Github

public class CacheInterceptor implements Interceptor {@Overridepublic Response intercept(Interceptor.Chain chain) throws IOException {Request request = chain.request();//如果没有网络,则启用 FORCE_CACHEif(!isNetworkConnected()) {request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();}Response originalResponse = chain.proceed(request);if(isNetworkConnected()) {//有网的时候读接口上的@Headers里的配置String cacheControl = request.cacheControl().toString();return originalResponse.newBuilder().header("Cache-Control", cacheControl).removeHeader("Pragma").build();} else {return originalResponse.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=3600").removeHeader("Pragma").build();}}public static boolean isNetworkConnected() {Context context = Retrofit2Utils.context;if (context != null) {ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();if (mNetworkInfo != null) {return mNetworkInfo.isAvailable();}}return false;}
}
  • 本篇博文上的代码已经共享到Github上,欢迎大家多多提意见

  • 参考文章

    1. Retrofit 源码解读之离线缓存策略的实现
    2. 【译】Retrofit 2 - 如何从服务器下载文件
    3. RxJava+Retrofit Samples解析
    4. Retrofit 2 + OkHttp 3 实现图片上传 (RxJava的方式)
    5. Retrofit笔记
    6. 使用Retrofit和Okhttp实现网络缓存。无网读缓存,有网根据过期时间重新请求
    7. Android Retrofit 2.0使用

当RxJava遇上Retrofit相关推荐

  1. OkHttpUtils-2.0.0 升级后改名 OkGo,全新完美支持 RxJava,比 Retrofit 更简单易用。

    okhttp-OkGo 项目地址:jeasonlzy/okhttp-OkGo 简介:OkHttpUtils-2.0.0 升级后改名 OkGo,全新完美支持 RxJava,比 Retrofit 更简单易 ...

  2. 推荐系统遇上深度学习,9篇阿里推荐论文汇总!

    作者 | 石晓文 转载自小小挖掘机(ID: wAIsjwj) 业界常用的推荐系统主要分为两个阶段,召回阶段和精排阶段,当然有时候在最后还会接一些打散或者探索的规则,这点咱们就不考虑了. 前面九篇文章中 ...

  3. 华为平板电脑_当5G遇上平板电脑,华为MatePad Pro 5G带来了什么?

    5G已经来临,科技产品向5G升级已是大势所趋,这更是检验实力的探索之路. 2月24日,华为在巴塞罗那在线发布了一系列新品,其中,华为面向全球推出的5G高端旗舰平板,同时也是全球首款公开发布的5G平板华 ...

  4. 404未找到是什么意思_为什么老遇上404 not found?你懂的

    文章转载自公众号:一只学霸(bajie203) 昨天晚上 大毛火急火燎地打开了电脑 戴上了耳机 不到两分钟 -- 我们往前一凑 登等 果然是大家最害怕的一幕出现了 学霸在网上冲浪多年 留下的都是美好的 ...

  5. 《当用户体验设计遇上敏捷》一3.5 小结

    本节书摘来自异步社区<当用户体验设计遇上敏捷>一书中的第3章,第3.5节,作者[英]Lindsay Ratcliffe , Marc McNeill,更多章节内容可以访问云栖社区" ...

  6. 当网络安全遇上大数据分析(9)

    2012年3月份,Gartner发表过一篇报告--Information Security Is Becoming a Big Data Analytics Problem .里面主要就讲到了针对大规 ...

  7. html实体编码遇上js代码

    单双引号 在js代码中 在js中单.双引号引起来的是字符串,如果我们要在字符串中使用单.双引号,需要反斜杠进行转义 let str='user\'s name'; // or let str=&quo ...

  8. SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败解决方案

    SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败的问题,可作如下尝试: 更新失败后,在windows的[事件查看器→应用程序]中找到来源为MsiInstaller,事件ID为1 ...

  9. 当微信小程序遇上TensorFlow:Server端实现补充

    在前面一篇文章<当微信小程序遇上TensorFlow:Server端实现>中,我们探讨了微信小程序server端的实现.今天在调试微信小程序时才发现一个问题,那就是:微信小程序要求HTTP ...

最新文章

  1. 新型智能电视攻击,9成国外设备或受影响
  2. 2005年个人防病毒软件评测报告
  3. 答疑 | 算法岗和开发岗有什么区别?
  4. 接口超时后程序还会继续执行嘛_答网友问:分析一段STL程序,并就如何读懂一段程序谈几点感想...
  5. win2003能装mysql_Windows2003系统安装mysql小结
  6. web.config mysql_web.config配置mysql数据库连接
  7. C++中全局函数和局部函数的关系
  8. Java 命令行编译项目
  9. Mysql Hunter
  10. css 中图片旋转,倾斜,位移,平滑
  11. mouted vue 操作dom_vue中关于dom的操作
  12. java类spring加载_spring的加载机制?
  13. tomcat 访问权限设置
  14. c++开发软件_Windows下学习C语言有哪些集成开发软件?
  15. java将英语单词进行词性分类排序_史上最全讲解,必须牢记的英语十类词性分类及用法!(上)...
  16. android 重力传感器gsensor,浅谈Android重力感应
  17. Vue+ElementUI+Tabs实现选项卡|标签页|美化标签页面|局部替换样式|好看的标签页|选项卡
  18. [转载]基于UML的需求分析和系统设计(完整案例和UML图形演示)
  19. Android腾讯开放平台应用认领
  20. 回收站删除了怎么恢复

热门文章

  1. CentOS 7 安装极点五笔输入法
  2. echarts显示中国地图
  3. 局域网访问提示无法访问检查拼写_无法访问局域网共享(win7访问xp):请检查名称的拼写.否则网络可能有问题. 错误代码0x80004005...
  4. 共享文件夹:请检查名称的拼写,否则,网络可能有问题错误代码0x80070035
  5. 编程之美之一摞烙饼的排序1
  6. dnf剑魂buff等级上限_DNF:全职业BUFF等级一览,深渊之鳞护肩宝珠别选错等级了
  7. 龙卷风迁徙地图,原来可以这样做
  8. SCC会员北京车展围拍超跑 却火了这款华为MateRS保时捷版手机
  9. 【codeforces 718E】E. Matvey's Birthday
  10. 4.5 没有自学,不是大学——《逆袭大学》连载