前言
Retrofit是一个网络请求,用法简洁方便,一起来学习一下吧O(∩_∩)O~
一、配置
工具是 Android Studio,所以这里只讲AndroidStudio的配置
**1. build.gradle **
首先,如图添加retrofit和okhttp
Paste_Image.png
compile 'com.squareup.retrofit2:retrofit:2.2.0'
compile 'com.squareup.okhttp3:okhttp:3.6.0'
2. 添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
二、静态参数接口GET请求
接口用http://gank.io/api/data/Android/10/1这个
然后,我们就开始获取数据啦~
1. 定义一个接口类
这个接口我们用https://..com/goods/tags/goods/1?g_id=0
public interface Api {
@GET("goods/tags/goods/1?g_id=0")
Call<ResponseBody> getData();
}
2. 开始请求
接口需要大家自己找一个写啦O(∩_∩)O~
1. 返回ResponseBody
Retrofit retrofit = new Retrofit.Builder().baseUrl(Api.baseUrl).build();
Api api = retrofit.create(Api.class);//创建接口对象
Call<ResponseBody> call = api.getData();
//开始异步请求
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
String data = response.body().string();
txt.setText(data);
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
t.printStackTrace();
}
});
结果
2. 返回解析后的对象
注意注意:必须创建一个转换器,才可以哦,不然会发现 Unable to create converter for ...的错误哦
-
添加转换器
compile 'com.squareup.retrofit2:converter-gson:2.2.0' - 根据gson解析工具建立实体类,不建议使用,原因后面说~
public class ResultBean {
...
private int id;
...
}
3.开始使用
把responseBody改成ResultBean,然后加上converter转换器就好
@GET("goods/tags/goods/1?g_id=0")
Call<ResultBean> getObjectBean();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
Api api = retrofit.create(Api.class);//创建接口对象
Call<ResultBean> call = api.getObjectBean();
//开始异步请求
call.enqueue(new Callback<ResultBean>() {
@Override
public void onResponse(Call<ResultBean> call, Response<ResultBean> response) {
ResultBean resultBean = response.body();
txt.setText(resultBean.getData().toString());
}
@Override
public void onFailure(Call<ResultBean> call, Throwable t) {
t.printStackTrace();
}
});
有没有人出错的?
尴尬了,为什么呢?因为gson解析错误,主要是因为服务器返回的数据应该是array:[],但是返回成了这样子的array:null,所以说,为了防止这种问题,就最好是使用responseBody,然后自己解析
三、动态参数接口GET请求
- 接口的最终样式是goods/tags/goods/1?g_id=0,这里我们将g_id的值动态改变
@GET("goods/tags/goods/1")
Call<ResponseBody> getGoodsData(@Query("g_id") int id);
...
Call<ResponseBody> call = api.getGoodsData(0);
...
- 将1?g_id=0都动态改变
@GET("goods/tags/goods/{page}")
Call<ResponseBody> getGoodsDataInfo(@Path("page") int page, @Query("g_id") int id);
Call<ResponseBody> call = api.getGoodsDataInfo(1,0);
- 动态添加不确定数量的参数和类型
@GET("goods/tags/goods/{page}")
Call<ResponseBody> getGoodsDataParams(@Path("page") int page,@QueryMap Map<String,Integer> params);
HashMap<String, Integer> hash = new HashMap<>();
hash.put("page",1);
hash.put("g_id", 0);
Call<ResponseBody> call = api.getGoodsDataParams(1, hash);
- 传数组
@GET("v1/enterprise/find")
Call<ResponseBody> getData(@Query("id") String id, @Query("linked[]") String... linked);
四、Post请求
由于没有接口,只能这样子啦
- Post表单提交
@FormUrlEncoded
@POST("user/edit")
Call<Result> editUser(@Field("id") int id, @Field("name") String name);
如果报了@Field parameters can only be used with form encoding这个错误,则需要使用 @FormUrlEncoded
api.editUser(1, "liuguilin").enqueue(new Callback<Result>() {
@Override
public void onResponse(Call<Result> call, Response<Result> response) {
if (response.body().getYes() == 0) {
Toast.makeText(MainActivity.this, "成功", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<Result> call, Throwable t) {
}
});
- Post传json格式
{
data:""
}
public class DataBean {
private String data;
...
}
@POST("user/data")
Call<ResponseBody> getData(@Body DataBean data);
- Post传文件-单个
@Multipart
@POST("file/create")
Call<ResponseBody> create(@Part("pictureName") RequestBody pictureName, @Part MultipartBody.Part picture);
RequestBody pictureNameBody = RequestBody.create(MediaType.parse(AppConstants.CONTENT_TYPE_FILE), "pictureName");
File picture= new File(path);
RequestBody requestFile = RequestBody.create(MediaType.parse(AppConstants.CONTENT_TYPE_FILE), picture);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part picturePart = MultipartBody.Part.createFormData("picture", picture.getName(), requestFile);
//调接口
create(pictureNameBody, picturePart);
- Post传文件-多个
@Multipart
@POST("files/create")
Call<ResponseBody> create(@Part("pictureName") RequestBody pictureName, @PartMap Map<String, RequestBody> params);
RequestBody pictureNameBody = RequestBody.create(MediaType.parse(AppConstants.CONTENT_TYPE_FILE), "pictureName");
File picture= new File(path);
RequestBody requestFile = RequestBody.create(MediaType.parse(AppConstants.CONTENT_TYPE_FILE), picture);
Map<String, RequestBody> params = new HashMap<>();
params.put("picture\"; filename=\"" + picture.getName() + "", requestFile);
//调接口
create(pictureNameBody, params);
五、添加Header
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
六、log信息拦截
compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(httpLoggingInterceptor);
}
七、完整配置
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(httpLoggingInterceptor);
}
initCache(builder);
initParameter(builder);
initTimeOut(builder);
//将这些配置设置给retrofit
OkHttpClient client = builder.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
Api api = retrofit.create(Api.class);//创建接口对象
//设置超时和重连
private void initTimeOut(OkHttpClient.Builder builder) {
//设置超时
builder.connectTimeout(15, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
//错误重连
builder.retryOnConnectionFailure(true);
}
//添加公共参数
private void initParameter(OkHttpClient.Builder builder) {
Interceptor parameterInterceptor = new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request request;
String method = originalRequest.method();
Headers headers = originalRequest.headers();
HttpUrl modifiedUrl = originalRequest.url().newBuilder()
.addQueryParameter("platform", "android")
.addQueryParameter("version", "1.0.0")
.build();
request = originalRequest.newBuilder().url(modifiedUrl).build();
return chain.proceed(request);
}
};
builder.addInterceptor(parameterInterceptor);
}
//设置缓存,无网络时,也能显示数据
private void initCache(OkHttpClient.Builder builder) {
File cacheFile = new File(this.getExternalCacheDir(), "cache");
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);//缓存文件50M
Interceptor interceptor = new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!netWorkIsAvailable) {//网络不可用
request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
}
else {//网络可用
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_NETWORK)
.build();
}
okhttp3.Response response = chain.proceed(request);
if (netWorkIsAvailable) {
int maxAge = 0;
response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)//覆盖服务器响应头的Cache-Control,用我们自己的,因为服务器响应回来的可能不支持缓存
.removeHeader("Pragma")//清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清无法生效
.build();
}
else {
int maxStale = 60 * 60 * 24 * 28;//无网络时,设置超时为4周
response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return response;
}
};
builder.cache(cache).addInterceptor(interceptor);
}
八、移除请求
call.cancel();
后记
Github:https://github.com/square/retrofit
官网文档:http://square.github.io/retrofit/
参考网址
Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava
Android Retrofit 2.0 使用-补充篇
Retrofit中如何正确的使用https?
网友评论