目前,Google对HttpClient的摒弃,虽然之前一段时间volley的得到一定的关注,但是后来关注度逐渐的降低,但是Retrofit的依然是各大的Android开发者使用作为网络请求的框架,而且retrofit对okhttp进行了很好的依赖。
Retrofit是由square公司开发的。square在github上发布了很多优秀的Android开源项目。例如:otto(事件总线),leakcanary(排查内存泄露),android-times-square(日历控件),dagger(依赖注入),picasso(异步加载图片),okhttp(网络请求),retrofit(网络请求)等等。更多square上的开源项目我们可以去square的GitHub进行查看。这次就来介绍一下retrofit的一些基本用法。retrofit是REST安卓客户端请求库。使用retrofit可以进行GET,POST,PUT,DELETE等请求方式
1、加入依赖
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'io.reactivex:rxjava:1.2.4'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'org.ligboy.retrofit2:converter-fastjson-android:2.1.0'
这些依赖中有对RxJava RxAndroid等的依赖。
retrofit通过使用注解来简化请求,大体分为以下几类:
1.用于标注请求方式的注解
2.用于标记请求头的注解
3.用于标记请求参数的注解
4.用于标记请求和响应格式的注解
注解 | 说明 |
---|---|
@GET | get请求 |
@POST | post请求 |
@PUT | put请求 |
@DELETE | delete请求 |
@PATCH | patch请求,该请求是对put请求的补充,用于更新局部资源 |
@HEAD | head请求 |
@OPTIONS | option请求 |
@HTTP | 通用注解,可以替换以上所有的注解,其拥有三个属性:method,path,hasBody |
注解 | 说明 |
---|---|
@Headers | 用于添加固定请求头,可以同时添加多个。通过该注解添加的请求头不会相互覆盖,而是共同存在 |
@Header | 作为方法的参数传入,用于添加不固定值的Header,该注解会更新已有的请求头 |
名称 | 说明 |
---|---|
@Body | 多用于post请求发送非表单数据,比如想要以post方式传递json格式数据 |
@Filed | 多用于post请求中表单字段,Filed和FieldMap需要FormUrlEncoded结合使用 |
@FiledMap | 和@Filed作用一致,用于不确定表单参数 |
@Part | 用于表单字段,Part和PartMap与Multipart注解结合使用,适合文件上传的情况 |
@PartMap | 用于表单字段,默认接受的类型是Map |
@Path | 用于url中的占位符 |
@Query | 用于Get中指定参数 |
@QueryMap | 和Query使用类似 |
@Url | 指定请求路径 |
名称 | 说明 |
---|---|
@FormUrlEncoded | 表示请求发送编码表单数据,每个键值对需要使用@Field注解 |
@Multipart | 表示请求发送multipart数据,需要配合使用@Part |
@Streaming | 表示响应用字节流的形式返回.如果没使用该注解,默认会把数据全部载入到内存中.该注解在在下载大文件的特别有用 |
Annotations on the interface methods and its parameters indicate how a request will be handled.
Every method must have an HTTP annotation that provides the request method and relative URL. There are five built-in annotations: GET
, POST
, PUT
, DELETE
, and HEAD
. The relative URL of the resource is specified in the annotation.
@GET("users/list")
You can also specify query parameters in the URL.
@GET("users/list?sort=desc")
A request URL can be updated dynamically using replacement blocks and parameters on the method. A replacement block is an alphanumeric string surrounded by {
and }
. A corresponding parameter must be annotated with @Path
using the same string.
@GET("group/{id}/users") Call<List<User>> groupList(@Path("id") int groupId);
Query parameters can also be added.
@GET("group/{id}/users") Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
For complex query parameter combinations a Map
can be used.
@GET("group/{id}/users") Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
An object can be specified for use as an HTTP request body with the @Body
annotation.
@POST("users/new") Call<User> createUser(@Body User user);
The object will also be converted using a converter specified on the Retrofit
instance. If no converter is added, only RequestBody
can be used.
Methods can also be declared to send form-encoded and multipart data.
Form-encoded data is sent when @FormUrlEncoded
is present on the method. Each key-value pair is annotated with @Field
containing the name and the object providing the value.
@FormUrlEncoded @POST("user/edit") Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
Multipart requests are used when @Multipart
is present on the method. Parts are declared using the @Part
annotation.
@Multipart @PUT("user/photo") Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
Multipart parts use one of Retrofit
's converters or they can implement RequestBody
to handle their own serialization.
You can set static headers for a method using the @Headers
annotation.
@Headers("Cache-Control: max-age=640000") @GET("widget/list") Call<List<Widget>> widgetList();
@Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App" }) @GET("users/{username}") Call<User> getUser(@Path("username") String username);
Note that headers do not overwrite each other. All headers with the same name will be included in the request.
A request Header can be updated dynamically using the @Header
annotation. A corresponding parameter must be provided to the @Header
. If the value is null, the header will be omitted. Otherwise, toString
will be called on the value, and the result used.
@GET("user") Call<User> getUser(@Header("Authorization") String authorization)
下面是我对Retrofit的进行初始化
Interceptor headerInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request().newBuilder()
.addHeader("Accept", "application/json")
.method(chain.request().method(), chain.request().body())
.build();
return chain.proceed(original);
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(headerInterceptor)
.connectTimeout(10000L, TimeUnit.MILLISECONDS)
.readTimeout(10000L, TimeUnit.MILLISECONDS)
.sslSocketFactory(BaseApplication.sslParams.sSLSocketFactory, BaseApplication.sslParams.trustManager)
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
})
.build();
jsonInstance = new Retrofit.Builder()
.client(client)
.baseUrl(Constants.APP_HOST)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return jsonInstance;
这里面有对拦截器的添加,可以根据自己的需要进行自行的添加,超时的设置也可以自行的设置。
因为我的项目中,需要添加Https的请求,所以我的有ssl的证书添加设置。等下会在后面的部分进行说明和使用方法的介绍。
@POST("users/companyLogin")
Observable
我这边是运用了Observable不是Call,感觉Call的回调有些麻烦,这里用到了RxJava进行处理
下面是请求结果的处理
Retrofit retrofit = RetrofitInstance.getJsonInstance();
LoginService service = retrofit.create(LoginService.class);
service.getLoginResponse(loginRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(LoginResponse value) {
listener.OnSuccess(value);
}
@Override
public void onError(Throwable e) {
listener.OnFailure(e);
}
@Override
public void onComplete() {
}
});
这已经是retrofit的一个基本的操作流程了。
项目中经常回用到上传使用,下面在简要的说明一下具体的方法:
上传:
public class RetrofitMutiPartTool { //Mutipart的String直接传会多一对引号,必须转成Requestbody才行 public static RequestBody toRequestBody(String value) { return RequestBody.create(MediaType.parse("text/plain"), value); } public static RequestBody toRequestBody(File value) { RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data"), value); return body; } public static RequestBody toRequestBody(byte[] value) { RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data"), value); return body; } }
private MultipartBody.Part Front(String path) { if (path != null) { file1 = new File(path); RequestBody fileBody1 = RetrofitMutiPartTool.toRequestBody(file1); MultipartBody.Part uploadFile1 = MultipartBody.Part.createFormData("uploadFile1", file1.getName(), fileBody1); return uploadFile1; } else { return null; }
请求的接口如下
@Multipart @POST(ProductURL.User_addIdentityInfo) ObservableaddIdentityInfor(@Part MultipartBody.Part uploadFile1, @Part MultipartBody.Part uploadFile2, @Part MultipartBody.Part uploadBiometric, @Query("uid") long uid, @Query("name") String name, @Query("mobile") String mobile, @Query("gender") String gender, @Query("birthday") String birthday, @Query("certAddress") String certAddress, @Query("certType") int certType, @Query("certNo") String certNo);
下面介绍的是使用https
public class HttpsUtils {
public static class SSLParams {
public SSLSocketFactory sSLSocketFactory;
public X509TrustManager trustManager;
}
public static SSLParams getSslSocketFactory(InputStream[] certificates, InputStream bksFile, String password) {
SSLParams sslParams = new SSLParams();
try {
TrustManager[] trustManagers = prepareTrustManager(certificates);
KeyManager[] keyManagers = prepareKeyManager(bksFile, password);
SSLContext sslContext = SSLContext.getInstance("TLS");
X509TrustManager trustManager = null;
//这里使用证书的时候要进行的验证,如果失败的话可以直接走trustManager = new UnSafeTrustManager();
if (trustManagers != null) {
// trustManager = new MyTrustManager(chooseTrustManager(trustManagers));
// } else {
// trustManager = new UnSafeTrustManager();
// }
trustManager = new UnSafeTrustManager();
sslContext.init(keyManagers, new TrustManager[]{trustManager}, null);
sslParams.sSLSocketFactory = sslContext.getSocketFactory();
sslParams.trustManager = trustManager;
return sslParams;
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (KeyManagementException e) {
throw new AssertionError(e);
}
// catch (KeyStoreException e) {
// throw new AssertionError(e);
// }
}
private class UnSafeHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
private static class UnSafeTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
private static TrustManager[] prepareTrustManager(InputStream... certificates) {
if (certificates == null || certificates.length <= 0) return null;
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try {
if (certificate != null)
certificate.close();
} catch (IOException e)
{
}
}
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.
getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
return trustManagers;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) {
try {
if (bksFile == null || password == null) return null;
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(bksFile, password.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, password.toCharArray());
return keyManagerFactory.getKeyManagers();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}
private static class MyTrustManager implements X509TrustManager {
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;
public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
var4.init((KeyStore) null);
defaultTrustManager = chooseTrustManager(var4.getTrustManagers());
this.localTrustManager = localTrustManager;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
}
HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(null, null, null);
sslParams是在Application oncreate的时候获取,然后在Retrofit 初始化的时候添加上去
OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(headerInterceptor) .connectTimeout(10000L, TimeUnit.MILLISECONDS) .readTimeout(10000L, TimeUnit.MILLISECONDS) .sslSocketFactory(BaseApplication.sslParams.sSLSocketFactory, BaseApplication.sslParams.trustManager) .hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslSession) { return true; } }) .build();这些都是在项目中用到的,如果觉得有用请点赞!!!