官网:http://square.github.io/retrofit/
官方定义:
A type-safe HTTP client for Android and Java
一:配置
app:build.gradle:
compile 'com.squareup.retrofit2:retrofit:2.0.2'
二:例子
–1:BaseResponse
public class BaseResponse {
String returnCode;
String msg;
String result;
boolean success;
public String getReturnCode() {
return returnCode;
}
public void setReturnCode(String returnCode) {
this.returnCode = returnCode;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
–2:HtppService
public interface HttpService {
@FormUrlEncoded
@POST("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Field("password") String password, @Field("phone") String phone);
}
–3:User
public class User {
private int id;
private boolean invalid;
private int status;
private long createdDatetime;
private long updatedDatetime;
private int orderTag;
private String name;
private String phone;
private String password;
private String slogan;
private String imagpath;
private int userid;
private int sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isInvalid() {
return invalid;
}
public void setInvalid(boolean invalid) {
this.invalid = invalid;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public long getCreatedDatetime() {
return createdDatetime;
}
public void setCreatedDatetime(long createdDatetime) {
this.createdDatetime = createdDatetime;
}
public long getUpdatedDatetime() {
return updatedDatetime;
}
public void setUpdatedDatetime(long updatedDatetime) {
this.updatedDatetime = updatedDatetime;
}
public int getOrderTag() {
return orderTag;
}
public void setOrderTag(int orderTag) {
this.orderTag = orderTag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSlogan() {
return slogan;
}
public void setSlogan(String slogan) {
this.slogan = slogan;
}
public String getImagpath() {
return imagpath;
}
public void setImagpath(String imagpath) {
this.imagpath = imagpath;
}
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
}
–4:BaseResponse
public class UserResponse extends BaseResponse {
private RespData data;
public RespData getData() {
return data;
}
public void setData(RespData data) {
this.data = data;
}
public static class RespData {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
}
–5:MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String WEB_URL = "http://192.168.1.115:8080";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.start).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start:
getUser();
break;
}
}
private void getUser() {
Retrofit retrofit = new Retrofit.Builder().baseUrl(WEB_URL).addConverterFactory(GsonConverterFactory.create()).build();
HttpService httpService = retrofit.create(HttpService.class);
String phone = "15029206553";
String password = "123456";
Call<UserResponse> call = httpService.getUserByLogin(password, phone);
call.enqueue(new Callback<UserResponse>() {
@Override
public void onResponse(Call<UserResponse> call, Response<UserResponse> response) {
Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();
}
@Override
public void onFailure(Call<UserResponse> call, Throwable t) {
}
});
}
}
注:可以看出,接口返回的是需要的JAVA对象,不是而不是byte[]或String!Retrofit内部默认使用Gson解析相关数据。
三:相关方法:
—-1:支持:GET, POST, PUT, DELETE, and HEAD!
@GET("users/list")
@GET("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Query("password") String password, @Query("phone") String phone);
也可以直接在请求接口中显示需要的参数,类似于:
@GET("users/list?sort=desc")
@GET("/frist/noIntercept/user/login.do?password=123456&phone=15029206553")
Call<UserResponse> getUserByLogin();
使用技巧:当我们使用POST方式无参去请求数据的时候,请修改为无参的GET请求。
- - 2:可以动态更新请求块里面的参数和方法,一个相应的参数必须和@Path保持同样的字符串
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
@GET("/frist/noIntercept/{user}/login.do?password=123456&phone=15029206553")
Call<UserResponse> getUserByLogin(@Path("user") String user);
也可以使用查询方法来添加相关参数,类似于:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
@GET("/frist/noIntercept/{user}/login.do")
Call<UserResponse> getUserByLogin(@Path("user") String user,@Query("password") String password, @Query("phone") String phone);
—-3:Map使用
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
使用技巧:对于复杂参数,可以使用Map来组合请求对象。
—-4:JavaBean作为请求体<添加转换器,若没有添加,只能使用response>
@POST("users/new")Call<User> createUser(@Body User user);
public class LoginBean {
String password;
String phone;
public LoginBean(String password, String phone){
this.password=password;
this.phone=phone;
}
}
@POST("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Body LoginBean loginBean);
String phone = "15029206553";
String password = "123456";
LoginBean loginBean=new LoginBean(password,phone);
Call<UserResponse> call = httpService.getUserByLogin(loginBean);
注意点:使用此种方式传参,需要修改后台正常获取参数的方式,慎用。
—-5:指定请求编码类型
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
@FormUrlEncoded
@POST("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Field("password") String password, @Field("phone") String phone);
—-6:操作Head
@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);
注:当@Headers{}为空时,则会自动忽略。
—-7:每个请求都添加Head:<动态更新>
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
—-8:使用ConverterFactory来修改默认返回数据解析<可自定义转换器>
Retrofit默认使用GSON进行相关数据解析。
下面是一个使用GsonConverterFactory生成JSON解析数据的例子:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
四:简单封装:
–1:RetrofitUtil:
public class RetrofitUtil {
private static final String WEB_URL = "http://192.168.1.115:8080";
public static HttpService instanceHttpService() {
Retrofit retrofit = new Retrofit.Builder().baseUrl(WEB_URL).addConverterFactory(GsonConverterFactory.create()).build();
HttpService httpService = retrofit.create(HttpService.class);
return httpService;
}
}
–2:MainActivity:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.start).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start:
getUser();
break;
}
}
private void getUser() {
String phone = "15029206553";
String password = "123456";
Call<UserResponse> call = RetrofitUtil.instanceHttpService().getUserByLogin(password, phone);
call.enqueue(new Callback<UserResponse>() {
@Override
public void onResponse(Call<UserResponse> call, Response<UserResponse> response) {
Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();
}
@Override
public void onFailure(Call<UserResponse> call, Throwable t) {
}
});
}
}
可以看出来:代码量减少很多。
五:深度封装:
拦截器是一个强大的机制,可以监视,重写,然后重新调用。
–1:
调用链的调用(请求)是每个拦截的执行的一个关键部分:
public class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
.....
// request.url(), chain.connection(), request.headers();
Response response = chain.proceed(request);
long t2 = System.nanoTime();
....
// response.request().url(), (t2 - t1) / 1e6d, response.headers();
return response;
}
}
–2:Application interceptors:
—-:拦截器分为应用拦截和网络:
打印拦截器:
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(logging)//添加打印拦截器
.connectTimeout(30, TimeUnit.SECONDS)//设置请求超时时间
.retryOnConnectionFailure(true)//设置出现错误进行重新连接。
.build();
注意:多了一个.client()方法:
Retrofit retrofit = new Retrofit.Builder().baseUrl(WEB_URL).client(httpClient).addConverterFactory(GsonConverterFactory.create()).build();
因为OKHTTP支持重定向,而Retrofit是基于OKHTTP3建立各种模块的。
–3:重定向
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
Request request = new Request.Builder()
.url("http://www.publicobject.com/helloworld.txt")
.header("User-Agent", "OkHttp Example")
.build();
Response response = client.newCall(request).execute();
response.body().close();
结果为:
INFO: Sending request http://www.publicobject.com/helloworld.txt on null
User-Agent: OkHttp Example
INFO: Received response for https://publicobject.com/helloworld.txt in 1179.7ms
Server: nginx/1.4.6 (Ubuntu)
Content-Type: text/plain
Content-Length: 1759
Connection: keep-alive
–4:网络监听器
.addNetworkInterceptor(new LoggingInterceptor())
应用和网络拦截器比对:
应用拦截器:
--1:不用担心请求时重定向和定向次数
--2:调用次数为一次<缓存>
--3:允许重试,多次调用请求链<okhttp请求是通过链路进行管理的>
--4:可以观察应用的意图,在请求或者返回数据的时候进行相关匹配以及处理
网络拦截器:
--1:观察数据传输
六:特殊需求:
–1:所有网络请求都添加token:
Interceptor mToken = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (You.token == null || alreadyHasAuthorizationHeader(originalRequest)) {
return chain.proceed(originalRequest);
}
Request authorised = originalRequest.newBuilder()
.header("Authorization", You.token)
.build();
return chain.proceed(authorised);
}
};
public static boolean alreadyHasAuthorizationHeader(Request request) {
if (request != null) {
if (request.headers() != null) {
return true;
} else {
return false;
}
}
return false;
}
–1:
—-:if判断,当你有token的时候才会进行添加,或者请求验证中已经有hrader了,那么就不执行这个token了。
—-:header 的 key 通常是 Authorization,可以修改
2–:添加公私密钥
MarvelSigningInterceptor signingInterceptor = new MarvelSigningInterceptor(KeyValue.MARVEL_PUBLIC_KEY, KeyValue.MARVEL_PRIVATE_KEY);
3–:添加缓存策略
File cacheFile = new File(context.getCacheDir(), "ZhiBookCache");
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor interceptorCache = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetworkStateUtils.getInstance(context).isConnection()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (NetworkStateUtils.getInstance(context).isConnection()) {
int maxAge = 0 * 60;
// 有网络时 设置缓存超时时间0个小时
response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
.build();
} else {
// 无网络时,设置超时为4周
int maxStale = 60 * 60 * 24 * 28;
response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return response;
}
};
七:再次封装:
–1:
public abstract class RCllBack<T> implements Callback<T> {
@Override
public void onResponse(Call<T> call, Response<T> response) {
onSuccess(response.body());
}
@Override
public void onFailure(Call<T> call, Throwable t) {
}
public abstract void onSuccess(T response);
}
–2:
public abstract class RCllBaackComm<T> implements Callback<T> {
@Override
public void onResponse(Call<T> call, Response<T> response) {
BaseResponse resp = (BaseResponse) response.body();
//在此可以根据自己的功能需求进行相关判断
}
@Override
public void onFailure(Call<T> call, Throwable t) {
onFailed(new CommError("网络错误"));
}
public abstract void onSuccess(T response);
public abstract void onFailed(CommError error);
}
概念理解:
onResponse: HTTP有效也就是请求返回为200,返回数据
因此在此方法里面,可以根据自己和服务器返回值的约定进行相关处理;
onFailure:当请求地址不存在或者其他原因<无网络>
以下为三种不同方法用起来的差异:
Call<UserResponse> call = RetrofitUtil.service.getUserByLogin(password, phone);
//1
call.enqueue(new Callback<UserResponse>() {
@Override
public void onResponse(Call<UserResponse> call, Response<UserResponse> response) {
Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();
}
@Override
public void onFailure(Call<UserResponse> call, Throwable t) {
}
});
//2
call.enqueue(new RCllBack<UserResponse>() {
@Override
public void onSuccess(UserResponse response) {
}
});
//3
call.enqueue(new RCllBaackComm<UserResponse>() {
@Override
public void onSuccess(UserResponse response) {
}
@Override
public void onFailed(CommError error) {
}
});
相关依赖引入:
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
compile 'com.squareup.okhttp3:okhttp:3.0.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'
本次源码获取地址:
github:https://github.com/erhutime/NetWorking