Android(安卓)Retrofit 2.0(一)初次见面请多多关照
前言
Retrofit 是SQUARE美国一家移动支付公司最近新发布的在Android平台上 Http 访问的开源项目。官方标语:“A type-safe HTTP client for Android and Java”语意很明显是一款Android 安全类型的http客户端。 这里安全指什么呢?是支持https或是支持本地线程安全呢?而且,Retrofit其内部都是支持lambda语法(链式语法),内部支持okHttp, 并且支持响应式RxJava,当然JDK 1.8 和 android studio工具也支持lambda。带着这些疑问 我开始探究一下。
Retrofit 官方GitHub地址
http://square.github.io/retrofit/
系列文章推荐:
Android 必须知道的网络请求框架库,你不可错过的框架介绍篇
Android Retrofit 2.0(一)初次见面请多多关照
Android Retrofit 2.0(二)使用教程OkHttp3 + Gson + RxJava
Android Retrofit 2.0(三)从源码分析原理
添加依赖
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返回的数据进行解析,下面会讲到。
基础使用
private void getLogin() { Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost:8080/") .addConverterFactory(GsonConverterFactory.create()) .build(); ApiManager apiService = retrofit.create(ApiManager.class); Call call = apiService.getData("lyk", "1234"); call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { if (response.isSuccess()) { // 请求成功 } else { //直接操作UI 或弹框提示请求失败 } } @Override public void onFailure(Call call, Throwable t) { //错误处理代码 } });}
ApiManager接口
public interface ApiManager { @GET("login/") Call getData(@Query("name") String name, @Query("password") String pw);
以上就是实现一个登录Login接口的小功能 ,先了解一下Retrofit的基本用法。
基础介绍
1、首先,实例化一个Retrofit对象。
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost:8080/") .addConverterFactory(GsonConverterFactory.create()) .build();
*addConverterFactory 制定数据解析器,上面添加依赖的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、然后,定义带参的请求接口
@GET("login/") Call getData(@Query("name") String name, @Query("password") String pw);
Call
接着我们可以传入制定的解析Modle,就会在主线程里返回对应的model数据,无需开发者手动解析json数据。返回格式由开发者自己设置。
这里主要用注解@get @post 设置请求方式,后面“login/”是方法Url, @Query("name")来设定body的parameters。
- 如果想用表单 @FieldMap
@FormUrlEncoded@POST("/url") Call
postForm( @FieldMap Map maps);
如果直接用对象 @Body
@POST("url") Call
PostBody( @Body Objects objects); 如果直接多参数 @QueryMap
@PUT("/url")Call
queryMap( @QueryMap Map maps); 如果上传文件 @Part
@Multipart@POST("/url")Call
uploadFlie( @Part("description") RequestBody description, @Part("files") MultipartBody.Part file);
如果多文件上传 @PartMap()
@Multipart@POST("{url}")Call
uploadFiles( @Path("url") String url, @PartMap() Map maps);
3、最后,调用API发起请求
Call call = apiService.getData("lyk", "1234"); call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { } @Override public void onFailure(Call call, Throwable t) { } });}
Retrofit支持异步和同步:
- call.enqueue(new Callback
)采用异步请求; - call.execute() 采用同步方式。
4、取消请求
call.cancel();
进阶练习
我们依然要面对的问题是 ,Retrofit 的内部怎么无法输出Log ?header怎么加入?请求怎么支持https?包括怎么结合RxJava? 不用担心,这些问题Retrofit 2.0 都提供了支持okhttp的自定义的Interceptor(拦截器)解决了。通过不同的拦截器可以实现不同的自定义请求形式,比如统一加head、参数、加入证书(ssl)等,前提必须结合okhttp来实现 , 通过给OkHttpClient添加Interceptor,然后给Retrofit设置http即可。Retrofit提供了.client()方法供我们自定义请求,当然默认请求就是okhttps的。
1、开启Log
用拦截器实现, retrofit已经提供了 HttpLoggingInterceptor 里面有四种级别,输出的格式,可以看下面介绍。
public enum Level { /** No logs. */ NONE, /** * Logs request and response lines. * * Example: *
{@code * --> POST /greeting http/1.1 (3-byte body) * * <-- 200 OK (22ms, 6-byte body) * }
*/ BASIC, /** * Logs request and response lines and their respective headers. * * Example: *
{@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 * }
*/ HEADERS, /** * Logs request and response lines and their respective headers and bodies (if present). * * Example: *
{@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 * }
*/ 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、增加头部信息
通用请求头
new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .client(new OkHttpClient.Builder() .addInterceptor(new Interceptor() { @Override public 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接口单独加入
@Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-your-App"})@get("users/{username}")Call getUser(@Path("username") String username);
3、添加证书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())
4、支持https
加密和普通http客户端请求支持https一样,步骤如下:
- CertificateFactory 得到Context.getSocketFactory;
- 添加证书源文件;
- 绑定到okhttpClient;
- 设置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();
构建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 retrofit = new Retrofit.Builder() .client(okHttpClient) .build();
如果信任所有https请求,
可以直接将OkHttpClient的HostnameVerifier设置为false
OkHttpClient client = new OkHttpClient(); client.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslSession) { return true; } }); TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public void checkClientTrusted( java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException { } @Override public void checkServerTrusted( java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException { } @Override public 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();
常规问题
1 url被转义
http://api.myapi.com/http%3A%2F%2Fapi.mysite.com%2Fuser%2Flist
请将@path改成@url
public interface APIService { @GET Call getUsers(@Url String url);}
或者:
public interface APIService { @GET("{fullUrl}") Call getUsers(@Path(value = "fullUrl", encoded = true) String fullUrl);}
2Method方法找不到
java.lang.IllegalArgumentException: Method must not be null
请指定具体请求类型@get @post等
public interface APIService { @GET Call getUsers(@Url String url);}
3Url编码不对,@fieldMap parameters must be use FormUrlEncoded
如果用fieldMap加上FormUrlEncoded编码
@POST()@FormUrlEncodedObservable executePost( @FieldMap Map maps);
上层需要转换将自己的map转换为FieldMap
@FieldMap(encoded = true) Map<String, Object> parameters,
4 paht和url一起使用
Using @Path and @Url paramers together with retrofit2
java.lang.IllegalArgumentException: @Path parameters may not be used with @Url. (parameter #4
如果你是这样的:
@GETCall getOrder(@Url String url, @Path("id") int id);
请在你的url指定占位符.url:
www.myAPi.com/{Id}
总结
看了以上的知识点你发现Retrofit同样支持RxJava,通过以下设置Call适配模式.就可以完美关联RxJava。
retrofit .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
更多相关文章
- Android(安卓)查看SharedPreferences中的数据
- Android下创建一个sqlite数据库
- Android下Content Provider使用
- 【Android(安卓)学习笔记】save data(1)—— SharedPreferences简
- android中JSON数据的读写方法
- Android使用facebook api(二)
- SQLite数据库(2):ANDROID工程中的使用
- Android之路之十一(SharedPreferences&SQLite数据库)
- 记android学习之路----android中对json数据的解析