本文主要是介绍Android--Retrofit浅入深出,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
官网: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";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.start).setOnClickListener(this);}@Overridepublic 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>() {@Overridepublic void onResponse(Call<UserResponse> call, Response<UserResponse> response) {Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();}@Overridepublic 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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.start).setOnClickListener(this);}@Overridepublic 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>() {@Overridepublic void onResponse(Call<UserResponse> call, Response<UserResponse> response) {Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();}@Overridepublic void onFailure(Call<UserResponse> call, Throwable t) {}});}
}
可以看出来:代码量减少很多。
五:深度封装:
拦截器是一个强大的机制,可以监视,重写,然后重新调用。
–1:
调用链的调用(请求)是每个拦截的执行的一个关键部分:
public class LoggingInterceptor implements Interceptor {@Overridepublic 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 ExampleINFO: 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() {@Overridepublic 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() {@Overridepublic 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> {@Overridepublic void onResponse(Call<T> call, Response<T> response) {onSuccess(response.body());}@Overridepublic void onFailure(Call<T> call, Throwable t) {}public abstract void onSuccess(T response);
}
–2:
public abstract class RCllBaackComm<T> implements Callback<T> {@Overridepublic void onResponse(Call<T> call, Response<T> response) {BaseResponse resp = (BaseResponse) response.body();//在此可以根据自己的功能需求进行相关判断}@Overridepublic 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>() {@Overridepublic void onResponse(Call<UserResponse> call, Response<UserResponse> response) {Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();}@Overridepublic void onFailure(Call<UserResponse> call, Throwable t) {}
});
//2
call.enqueue(new RCllBack<UserResponse>() {@Overridepublic void onSuccess(UserResponse response) {}
});
//3
call.enqueue(new RCllBaackComm<UserResponse>() {@Overridepublic void onSuccess(UserResponse response) {}@Overridepublic 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--Retrofit浅入深出的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!