您的位置:首页 > 移动开发 > Android开发

Android--Retrofit浅入深出

2016-06-15 15:46 411 查看
官网: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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android java app