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:
二:例子
–1:BaseResponse
–2:HtppService
–3:User
–4:BaseResponse
–5:MainActivity
注:可以看出,接口返回的是需要的JAVA对象,不是而不是byte[]或String!Retrofit内部默认使用Gson解析相关数据。
三:相关方法:
—-1:支持:GET, POST, PUT, DELETE, and HEAD!
也可以直接在请求接口中显示需要的参数,类似于:
使用技巧:当我们使用POST方式无参去请求数据的时候,请修改为无参的GET请求。
- - 2:可以动态更新请求块里面的参数和方法,一个相应的参数必须和@Path保持同样的字符串
也可以使用查询方法来添加相关参数,类似于:
—-3:Map使用
使用技巧:对于复杂参数,可以使用Map来组合请求对象。
—-4:JavaBean作为请求体<添加转换器,若没有添加,只能使用response>
注意点:使用此种方式传参,需要修改后台正常获取参数的方式,慎用。
—-5:指定请求编码类型
—-6:操作Head
也可以写成下面:
注:当@Headers{}为空时,则会自动忽略。
—-7:每个请求都添加Head:<动态更新>
—-8:使用ConverterFactory来修改默认返回数据解析<可自定义转换器>
Retrofit默认使用GSON进行相关数据解析。
下面是一个使用GsonConverterFactory生成JSON解析数据的例子:
四:简单封装:
–1:RetrofitUtil:
–2:MainActivity:
可以看出来:代码量减少很多。
五:深度封装:
拦截器是一个强大的机制,可以监视,重写,然后重新调用。
–1:
调用链的调用(请求)是每个拦截的执行的一个关键部分:
–2:Application interceptors:
—-:拦截器分为应用拦截和网络:
打印拦截器:
因为OKHTTP支持重定向,而Retrofit是基于OKHTTP3建立各种模块的。
–3:重定向
结果为:
–4:网络监听器
应用和网络拦截器比对:
六:特殊需求:
–1:所有网络请求都添加token:
–1:
—-:if判断,当你有token的时候才会进行添加,或者请求验证中已经有hrader了,那么就不执行这个token了。
—-:header 的 key 通常是 Authorization,可以修改
2–:添加公私密钥
3–:添加缓存策略
七:再次封装:
–1:
–2:
概念理解:
onResponse: HTTP有效也就是请求返回为200,返回数据
因此在此方法里面,可以根据自己和服务器返回值的约定进行相关处理;
onFailure:当请求地址不存在或者其他原因<无网络>
以下为三种不同方法用起来的差异:
相关依赖引入:
本次源码获取地址:
github:https://github.com/erhutime/NetWorking
官方定义:
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
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法