http: //blog.csdn.net/sk719887916/article/details/51597816
Tamic首发


前阵子看到圈子里Retrofit 2.0,RxJava(Android), OkHttp3.3 ,加之支持android和 iOS 的React Native , 火的不要不要的, 2015年新技术一大波来袭 ,看着自己项目还在用HttpClient, AsyncTask的原生开发 感觉自己已成火星人,实在顶不住内心的自卑压力,加之对新技术的追求,入手移动开发新三剑客,虽然目前关于他们的目前介绍的资料一大把,但是自己亲自实践后,发现坑不少,为了能方便其他人安全顺利入坑,今天就先从Retrofit说起,前方高能,准备躲避。

Retrofit 2.0

Retrofit是SQUARE美国一家移动支付公司最近新发布的在Android平台上http访问的开源项目


一 什么Retrofit

官方标语;A type-safe HTTP client for Android and Java
语意很明显一款android安全类型的http客户端, 那么怎么样才算安全?支持https?支持本地线程安全?
发现Rertofit其内部都是支持lambda语法(国内称只链式语法),内部支持okhttp, 并且支持响应式RxJAava,当然jdk1.8 和android studio工具也支持lambda。带着这些疑问 我开始探究一下。

在此之前准备入手资料:

国外博客
https://inthecheesefactory.com/blog/retrofit-2.0/en

官方github
http://square.github.io/retrofit/

二 Retrofit怎么使用

下文之前先给大家看下传统的httpclient(url) + AsyncTask实现的登录功能,这样我们才能发现Retrofit的优雅之处.

不优雅之处请阅读:http://blog.csdn.net/sk719887916/article/details/53613263

传统方式:

  /*** Represents an asynchronous login/registration task used to authenticate* the user.*/
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {private final String mEmail;private final String mPassword;UserLoginTask(String email, String password) {mEmail = email;mPassword = password;}@Overrideprotected Boolean doInBackground(Void... params) {// TODO: attempt authentication against a network service.try {// Simulate network access.String result = "";BufferedReader in = null;String path ="http://localhost:8080/login/?" +"email =" + mEmail + "& password =" + mPassword;URL url =new URL(path);HttpURLConnection conn = (HttpURLConnection)url.openConnection();conn.setConnectTimeout(5 * 1000);conn.setRequestMethod("GET");InputStream inStream = conn.getInputStream();in = new BufferedReader(new InputStreamReader(conn.getInputStream()));String line;while ((line = in.readLine()) != null){result += "\n" + line;}}catch (MalformedURLException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (ProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}for (String credential : DUMMY_CREDENTIALS) {String[] pieces = credential.split(":");if (pieces[0].equals(mEmail)) {// Account exists, return true if the password matches.return pieces[1].equals(mPassword);}}// TODO: register the new account here.return true;}@Overrideprotected void onPostExecute(final Boolean success) {mAuthTask = null;if (success) {// do SomeThing} else {mPasswordView.setError(getString(R.string.error_incorrect_password));mPasswordView.requestFocus();}}@Overrideprotected void onCancelled() {mAuthTask = null;showProgress(false);}
}private void enterhome() {Intent intent = new Intent(LoginActivity.this, MainListActivity.class);startActivity(intent);
}

发现原理也很简单,点击loginbtn开启一个异步线程 在AsyncTaskdoInBackground中访问登录API,在onPostExecute中进行UI更新;也能很简单流畅的解决UI线程请求网络 非UI线程更新UI的问题, 但是AsyncTask 处理大数据耗时就会有弊端,况且他默认线程也是5个,容易造成泄漏,接下来介绍用Retrofit实现以上相同的功能的方式

2 Rxtrofit

  /*** 登录!*/
private  void getLogin() {Retrofit retrofit = new Retrofit.Builder().baseUrl("http://localhost:8080/").addConverterFactory(GsonConverterFactory.create()).build();ApiManager apiService = retrofit.create(ApiManager.class);Call<LoginResult> call = apiService.getData("lyk", "1234");call.enqueue(new Callback<LoginResult>() {@Overridepublic void onResponse(Call<LoginResult> call, Response<LoginResult> response) {if (response.isSuccess()) {// do SomeThing} else {//直接操作UI}}@Overridepublic void onFailure(Call<LoginResult> call, Throwable t) {// do onFailure代码}});
}

ApiManager接口

/*** Created by LIUYONGKUI on 2016-05-03.
*/
public interface ApiManager {@GET("login/")Call<LoginResult> getData(@Query("name") String name, @Query("password") String pw);

好了 看了以上代码 或许你已经看到了他的链式优雅高大上的地方了,也许看不懂,也许会懵逼 但没关系我们继续入门。

1 配置gradle

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'

com.squareup.retrofit2:converter-gson:2.0.0-beta4 此依赖非必须,只是方便我对http返回的数据进行解析。

2 定义实例化

1》初始化Retrofit

 Retrofit retrofit = new Retrofit.Builder().baseUrl("http://localhost:8080/").addConverterFactory(GsonConverterFactory.create()).build();

通过 Retrofit.Builder 来创建一个retrofit客户端,接着添加host url, 然后制定数据解析器,上面依赖的gson就是用在这里做默认数据返回的, 之后通过build()创建出来
Retrofit也支持且内部自带如下格式:

  • Gson: com.squareup.retrofit2:converter-gson
  • Jackson: com.squareup.retrofit2:converter-jackson
  • Moshi: com.squareup.retrofit2:converter-moshi
  • Protobuf: com.squareup.retrofit2:converter-protobuf
  • Wire: com.squareup.retrofit2:converter-wire
  • Simple XML: com.squareup.retrofit2:converter-simplexml
  • Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

2》编写API

  @GET("login/")Call<LoginResult> getData(@Query("name") String name, @Query("password") String pw);

Call是支持Cloneable序列化的 并支持泛型,且此类Retrofit统一返回对象,支持Callback回调,我们可以传入制定的解析Modle,就会在主线程里返回对应的model数据,这里主要用注解@get @post s设置请求方式,后面**“login/”**是方法Url, @Query(“name”)来设定body的parameters.

3》 调用API
Retrofit支持异步和同步,这里我们用call.enqueue(new Callback来采用异步请求,如果 call.execute() 则采用同步方式

   Call<LoginResult> call = apiService.getData("lyk", "1234");call.enqueue(new Callback<LoginResult>() {@Overridepublic void onResponse(Call<LoginResult> call, Response<LoginResult> response) {}@Overridepublic void onFailure(Call<LoginResult> call, Throwable t) {}});
}

取消请求
取消请求

直接用call实例进行cancel即可

  call.cancel();

优雅的取消请看Retrofit 2.0 超能实践(九)Rxjava结合Retrofit,如何优雅的取消请求!

如果还未理解请阅读参考入门资料:Retrofit 2.0:有史以来最大的改进

如果还未理解请阅读参考入门资料:Retrofit 2.0:有史以来最大的改进

三 进阶拓展

通过以上的介绍和案列,我们了解了怎样运用Retrofit请求网络数据,展现数据更新UI,但实际开发中会存在很多问题,很多同学会遇到:Retrofit的内部Log都无法输出 , header怎么加入,请求怎么支持https,包括怎么结合RxJava.? 不用担心,这些Retrofit 2.0 都给我提供了自定义的Interceptor(拦截器),通过不同的Interceptor可以实现不同的自定义请求形式,比如统一加head,参数,加入证书(ssl)等,前提必须结合okhttp来实现 , 通过给OkHttpClient添加Interceptor,然后给Retrofit设置http客户端即可.Retrofit提供了
.client()方法供我们传入自定义的网络客户端,当然默然就是okhttps. 如果无法自动导包 需要我们自己添加对okhttp的依赖

compile ‘com.squareup.okhttp3:okhttp:3.3.1’

OkHttp入门请移步:

~https://github.com/square/okhttp
OKHttp源码解析

1 开启Log

可以用拦截器自己实现, retrofit已经提供了HttpLoggingInterceptor 里面有四种级别,输出的格式 可以看下面介绍。


public enum Level {/** No logs. */NONE,/*** Logs request and response lines.** <p>Example:* <pre>{@code* --> POST /greeting http/1.1 (3-byte body)** <-- 200 OK (22ms, 6-byte body)* }</pre>*/BASIC,/*** Logs request and response lines and their respective headers.** <p>Example:* <pre>{@code* --> POST /greeting http/1.1* Host: example.com* Content-Type: plain/text* Content-Length: 3* --> END POST** <-- 200 OK (22ms)* Content-Type: plain/text* Content-Length: 6* <-- END HTTP* }</pre>*/HEADERS,/*** Logs request and response lines and their respective headers and bodies (if present).** <p>Example:* <pre>{@code* --> POST /greeting http/1.1* Host: example.com* Content-Type: plain/text* Content-Length: 3** Hi?* --> END GET** <-- 200 OK (22ms)* Content-Type: plain/text* Content-Length: 6** Hello!* <-- END HTTP* }</pre>*/BODY}

开启请求头

     Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient.Builder().addNetworkInterceptor(new   HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS))       .build())

开启body日志

.addNetworkInterceptor(new   HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))

基础输出

 .addNetworkInterceptor(new   HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC))

2 增加头部信息

统一通用header

 new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create()).client(new OkHttpClient.Builder().addInterceptor(new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request().newBuilder().addHeader("mac", "f8:00:ea:10:45").addHeader("uuid", "gdeflatfgfg5454545e").addHeader("userId", "Fea2405144").addHeader("netWork", "wifi").build();return chain.proceed(request);}}).build()

当然可以对单一的某个API加入header

@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-your-App"})‘
@get("users/{username}")
Call<User> getUser(@Path("username") String username);

添加参数见:http://blog.csdn.net/sk719887916/article/details/52189602

3设置代理

   Proxy proxy = new Proxy(Proxy.Type.HTTP,  new InetSocketAddress(proxyHost, proxyPort));
OkHttpClient client = new OkHttpClient.Builder().proxy(proxy).build();Retrofit.Builder builder = new Retrofit.Builder().client(client);
Retrofit retrofit = builder.build();

4 添加证书Pinning

证书可以在自定义的OkHttpClient加入certificatePinner 实现

OkHttpClient client = new OkHttpClient.Builder().certificatePinner(new CertificatePinner.Builder().add("YOU API.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=").add("YOU API..com", "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=").add("YOU API..com", "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=").add("YOU API..com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=").build())

5 支持https

加密和普通http客户端请求支持https一样,步骤如下:

1 CertificateFactory 得到Context.getSocketFactory
2 添加证书源文件
3 绑定到okhttpClient
4设置okhttpClient到retrofit中

证书同样可以设置到okhttpclient中,我们可以把证书放到raw路径下

   SLSocketFactory sslSocketFactory =getSSLSocketFactory_Certificate(context,"BKS", R.raw.XXX);

准备证书源文件:

加入证书源文件,我的证书是放在Raw下面的:

绑定证书

protected static SSLSocketFactory getSSLSocketFactory(Context context, int[] certificates) {if (context == null) {throw new NullPointerException("context == null");}CertificateFactory certificateFactory;try {certificateFactory = CertificateFactory.getInstance("X.509");KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());keyStore.load(null, null);for (int i = 0; i < certificates.length; i++) {InputStream certificate = context.getResources().openRawResource(certificates[i]);keyStore.setCertificateEntry(String.valueOf(i), certificateFactory.generateCertificate(certificate));if (certificate != null) {certificate.close();}}SSLContext sslContext = SSLContext.getInstance("TLS");TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(keyStore);sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());return sslContext.getSocketFactory();

指定支持的host

/**
* set HostnameVerifier
* {@link HostnameVerifier}
*/
protected static HostnameVerifier getHostnameVerifier(final String[] hostUrls) {

        HostnameVerifier TRUSTED_VERIFIER = new HostnameVerifier() {public boolean verify(String hostname, SSLSession session) {boolean ret = false;for (String host : hostUrls) {if (host.equalsIgnoreCase(hostname)) {ret = true;}}return ret;}};return TRUSTED_VERIFIER;
}

设置setSocketFactory

okhttpBuilder.socketFactory(HttpsFactroy.getSSLSocketFactory(context,   certificates));

certificates 是你raw下证书源ID, int[] certificates = {R.raw.myssl}

设置setNameVerifie

 okhttpBuilder.hostnameVerifier(HttpsFactroy.getHostnameVerifier(hosts));

hosts是你的host数据 列如 String hosts[]`= {“https//:aaaa,com”, “https//:bbb.com”}

实现自定义 添加到Retrofit

        okHttpClient = okhttpBuilder.build();retrofit = new Retrofit.Builder().client(okHttpClient).build();

##忽略所有https

如果忽略所有https请求,
可以直接将OkHttpClient的HostnameVerifier设置为true

OkHttpClient client = new OkHttpClient();client.setHostnameVerifier(new HostnameVerifier() {@Overridepublic boolean verify(String s, SSLSession sslSession) {return true;}});TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {@Overridepublic void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates,String s) throws java.security.cert.CertificateException {}@Overridepublic void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates,String s) throws java.security.cert.CertificateException {}@Overridepublic java.security.cert.X509Certificate[] getAcceptedIssuers() {return new java.security.cert.X509Certificate[] {};}} };try {SSLContext sc = SSLContext.getInstance("TLS");sc.init(null, trustAllCerts, new java.security.SecureRandom());client.setSslSocketFactory(sc.getSocketFactory());} catch (Exception e) {e.printStackTrace();}clent.protocols(Collections.singletonList(Protocol.HTTP_1_1)).build();

总结

看了以上的知识点你发现Retrofit同等支持RxJava,通过以下Call适配模式.就可以关联RxJava

 retrofit .addCallAdapterFactory(RxJavaCallAdapterFactory.create())

关于 Retrofit+ RxJava的案列,以及实际遇到的坑下篇再介绍。RxJava也是一款强大的多线程通讯利器,让你的应用开发中无时无刻,随心所欲进行多线程响应式编程开发。

参考文章:

  • OkHttp使用教程
  • https://inthecheesefactory.com/blog/retrofit-2.0/en
  • 支持原文:
  • http://blog.csdn.net/sk719887916/article/details/51597816

Retrofit系列:

  • Retrofit 2.0(一) 超能实践,完美支持Https传输

  • Retrofit2.0(二) 完美同步Cookie实现免登录

  • Retrofit 2.0 超能实践(三),轻松实现文件/图片上传

  • Retrofit 2.0 超能实践(四),完成大文件断点下载

  • 基于Retrofit2.0 封装的超好用的RetrofitClient工具类

  • 玩转IOC,教你徒手实现自定义的Retrofit框架

强烈推荐:

  • Novate:对Retrofit2.0和RxJava2.0的又一次完美改进加强!(九)

欢迎关注个人公众号:

更多原创关注开发者技术前线

Retrofit 2.0 超能实践(一),okHttp完美支持Https传输相关推荐

  1. Retrofit 2.0 超能实践(三),轻松实现多文件/图片上传/Json字符串/表单

    通过前两篇姿势的入门 Retrofit 2.0 超能实践,完美支持Https传输 Retrofit2.0 完美同步Cookie实现免登录 本文出自:http://blog.csdn.net/sk719 ...

  2. Retrofit 2.0 超能实践(四),完成大文件断点下载

    作者:码小白 文/CSDN 博客 本文出自:http://blog.csdn.net/sk719887916/article/details/51988507 码小白 通过前几篇系统的介绍和综合运用, ...

  3. OkGo - OkHttpUtils-2.0.0 升级后改名 OkGo,全新完美支持RxJava

    使用说明参考:https://github.com/jeasonlzy/okhttp-OkGo 实测相当不错,推荐给大家 该库是封装了okhttp的标准RESTful风格的网络框架,可以与RxJava ...

  4. Retrofit 2.0 轻松实现多文件/图片上传/Json字符串/表单

    如果嫌麻烦直接可以用我封装好的库:Novate: https://github.com/Tamicer/Novate 通过对Retrofit2.0的前两篇的基础入门和案例实践,掌握了怎么样使用Retr ...

  5. Retrofit 2.0:有史以来最大的改进

    因为其简单与出色的性能,Retrofit 是安卓上最流行的HTTP Client库之一. 不过它的缺点是在Retrofit 1.x中没有直接取消正在进行中任务的方法.如果你想做这件事必须手动杀死,而这 ...

  6. 【Android】Retrofit 2.0 的使用

    一.概述 Retrofit是Square公司开发的一个类型安全的Java和Android 的REST客户端库.来自官网的介绍: A type-safe HTTP client for Android ...

  7. Retrofit 2.0

    1.简介 2.使用介绍 1:添加Retrofit库的依赖  1. 在 Gradle加入Retrofit库的依赖        build.gradle dependencies {compile 'c ...

  8. Android:手把手带你深入剖析 Retrofit 2.0 源码

    前言 在Andrroid开发中,网络请求十分常用 而在Android网络请求库中,Retrofit是当下最热的一个网络请求库 今天,我将手把手带你深入剖析Retrofit v2.0的源码,希望你们会喜 ...

  9. 随机森林的特征 是放回抽样么_机器学习超详细实践攻略(10):随机森林算法详解及小白都能看懂的调参指南...

    一.什么是随机森林 前面我们已经介绍了决策树的基本原理和使用.但是决策树有一个很大的缺陷:因为决策树会非常细致地划分样本,如果决策树分得太多细致,会导致其在训练集上出现过拟合,而如果决策树粗略地划分样 ...

最新文章

  1. Ubuntu Dapper 提速脚本
  2. SAP UI5关于navigation API的boolean参数
  3. 关于meta便签详解
  4. Deep Learning for Brain MRI Segmentation: State of the Art and Future Directions
  5. 对Linux 目录的认识
  6. 【hadoop】hadoop 血缘解析
  7. disk磁盘管理与Linux驱动编写
  8. 第一节补充: 按键操作(CubeMX加HAL库学STM32系列)
  9. Yahoo!用户体验与设计前副总裁推荐——《设计模式》
  10. python基于协程的网络库gevent、eventlet
  11. 陕西2020行政区划调整_2020西安会成立直辖市
  12. U盘解决 日立硬盘 c1门
  13. cmd下载的python包,pycharm中却无法使用
  14. Uphone开发心得
  15. win10屏幕亮度调节不见了,调节不了,解决办法
  16. 研究生学历会是我职业生涯的遮羞布吗
  17. 苹果ios按键精灵deb包旧版本1.3.8安装方法 --- 越狱通用版
  18. 2018初中计算机考试知识点,2018计算机等级考试考点:考前学习的技巧
  19. 如何修炼成某一领域的高手?
  20. 信息学奥赛一本通(基础算法与数据结构-题解汇总目录)

热门文章

  1. 笔记本故障:输入密钥界面没有文字
  2. ubuntu 8.10安装配置经验(转载)
  3. centos7 SSH服务启动时报“main process exited, code=exited”status 255错误
  4. 4.0低功耗蓝牙解决方案
  5. 工作居住证离职后应对
  6. stm32毕设 stm32人体健康状态检测系统(项目开源)
  7. 1,10-菲啰啉是氧化还原指示剂|双齿配体各类反应
  8. 图解HTTP(四)—— 返回结果的HTTP状态码
  9. 学计算机选择什么编程语言好一些?
  10. 刷题学习—算法思想(双指针、排序、回溯、二分法、滑动窗口、贪心、单调栈)