Retrofit入门
来源:互联网 发布:mysql left join 优化 编辑:程序博客网 时间:2024/06/06 02:09
导包
module: //retrofit 和Gson转换,由于retrofit是基于okhttp所以,还需要添加okhttp的依赖 compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.squareup.okhttp3:okhttp:3.4.1'
基本使用+Gson转换
api:https://api.github.com/users/baiiu
Json解析的model类,这里没有写出get set方法:public class User { private String login; private int id; private String avatar_url; private String gravatar_id; private String url; private String html_url; private String followers_url; private String following_url; private String gists_url; private String starred_url; private String subscriptions_url; private String organizations_url; private String repos_url; private String events_url; private String received_events_url; private String type; private boolean site_admin; private String name; private Object company; private String blog; private String location; private Object email; private boolean hireable; private String bio; private int public_repos; private int public_gists; private int followers; private int following; private String created_at; private String updated_at;}
定义接口public interface GitHubAPI { //get请求,请求接口为 baseurl(在代码中定义)+user/{user}({user}为在请求时传入的字符串) @GET("users/{user}") Call<User> userInfo(@Path("user") String user);}
使用方法//以okhttp为client对象OkHttpClient client = new OkHttpClient();//创建retrofit对象 Retrofit retrofit = new Retrofit.Builder() //设置OKHttpClient .client(client) //设置baseUrl,注意,baseUrl必须以后缀"/"结尾,否则报错 .baseUrl("https://api.github.com/") //添加Gson转换器,将接口返回的数据转换为jsonmodel对象 .addConverterFactory(GsonConverterFactory.create()) .build();//API对象,表示不同的apiGitHubAPI gitHubAPI = retrofit.create(GitHubAPI.class);//创建call对象,表示请求<User> userCall = gitHubAPI.userInfo("baiiu");//异步请求,也就是在不同线程 userCall.enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { User body = response.body(); Log.v("meee", getClass() + ":\n" + "body:" + body.toString()); //但callback是在主线程中的 Log.v("meee",getClass()+":\n"+"线程:"+Thread.currentThread().getName()); } @Override public void onFailure(Call<User> call, Throwable t) { if (call.isCanceled()) { Log.v("meee",getClass()+":\n"+"请求被终止"); } else { Log.v("meee",getClass()+":\n"+""+t.getMessage()); } } });//同步请求,与发起请求在同一个线程 //因为每一个call对象只能被使用一次,而userCall在上面已经被使用过了,所以克隆一个请求 Call<User> userCallClone = userCall.clone(); Response<User> response = userCallClone.execute();//需要处理io异常 response.body().toString();//因为在主线程调用,所以会报错
不使用Gson转换
public interface GitHubAPI {//直接返回okhttp的ResponseBody @GET Call<ResponseBody> raw(@Url String url);}
完整网址的请求
因为总有api是不同的,有时候为其生成独立api很麻烦,所以我们可以直接传入全路径网址来进行请求api接口中添加一个传入全路径url的接口方法public interface GitHubAPI { /*https://api.github.com/users/baiiu*/ @GET("users/{user}") Call<User> userInfo(@Path("user") String user); //该方法会跳过BasrUrl @GET Call<User> url(@Url String url);}//在请求时传入完整的网址 Call<User> url = gitHubAPI.url("https://api.github.com/users/baiiu"); url.enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { User body = response.body(); Log.v("meee", getClass() + ":\n" + "url:" + body.toString()); } @Override public void onFailure(Call<User> call, Throwable t) { } });
Post请求
public interface MallAPI { //使用@Field注解时一定要添加@FormUrlEncoded注解,否则报错 @FormUrlEncoded //post不能和@Url注解同时使用 @POST("login") Call<ResponseBody> login(@Field("username")String username, @Field("pwd") String pwd);}
MallAPI mallAPI = retrofit2.create(MallAPI.class); Call<ResponseBody> loginCall = mallAPI.login("123","123456"); loginCall.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { ResponseBody body = response.body(); try { Log.v("meee",getClass()+":\n"+""+body.string()); } catch (IOException e) { } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { } });
也可以使用属性map来传递参数public interface MallAPI { @FormUrlEncoded @POST("login") Call<ResponseBody> login(@FieldMap Map<String,String>map);}//创建call对象Call<ResponseBody> loginCall = mallAPI.login(map);
添加请求头
public interface GitHubAPI { //静态设置请求头,同一个请求的同一个请求头在不同地方的设置不会被覆盖,而是会被全部添加进请求头中 @Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App" }) @GET Call<User> urlWithHeaderStatic(@Url String url); //动态设置请求头 Call<User> urlWithHeaderDynamic(@Url String url,@Header("Authorization") String authorization);}
Interceptors的使用
导包,因为retrofit底层是使用okhttp,所以使用okhttp的Interceptors //okhttp拦截请求日志 compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
//创建Interceptor public final class UserAgentInterceptor implements Interceptor { private static final String USER_AGENT_HEADER_NAME = "User-Agent"; private final String userAgentHeaderValue; public UserAgentInterceptor(String userAgentHeaderValue) { this.userAgentHeaderValue = userAgentHeaderValue; } @Override public okhttp3.Response intercept(Chain chain) throws IOException { final Request originalRequest = chain.request(); final Request requestWithUserAgent = originalRequest.newBuilder() //移除先前默认的UA .removeHeader(USER_AGENT_HEADER_NAME) //设置UA .addHeader(USER_AGENT_HEADER_NAME, userAgentHeaderValue) .build(); return chain.proceed(requestWithUserAgent); } }
//在创建client时,传入创建的Interceptor OkHttpClient okHttpClient = new OkHttpClient.Builder() //添加UA .addInterceptor(new UserAgentInterceptor("header")) //失败重连 .retryOnConnectionFailure(true) //time out .readTimeout(10, TimeUnit.SECONDS) .connectTimeout(10, TimeUnit.SECONDS) .build();
混淆规则
/** -dontwarn retrofit2.*** -keep class retrofit2.** { *; }* -keepattributes Signature* -keepattributes Exceptions* */
注解详解
http类:
其中http注解可以代替以上7中的http标准注解public interface BlogService { /** * method 表示请求的方法,区分大小写 * path表示路径 * hasBody表示是否有请求体 */ @HTTP(method = "GET", path = "blog/{id}", hasBody = false) Call<ResponseBody> getBlog(@Path("id") int id);}
标记类
public interface BlogService { /** * {@link FormUrlEncoded} 表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded) * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值 */ @POST("/form") @FormUrlEncoded Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age); /** * Map的key作为表单的键 */ @POST("/form") @FormUrlEncoded Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map); /** * {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型 * 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息), */ @POST("/form") @Multipart Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file); /** * PartMap 注解支持一个Map作为参数,支持 {@link RequestBody } 类型, * 如果有其它的类型,会被{@link retrofit2.Converter}转换,如后面会介绍的 使用{@link com.google.gson.Gson} 的 {@link retrofit2.converter.gson.GsonRequestBodyConverter} * 所以{@link MultipartBody.Part} 就不适用了,所以文件只能用<b> @Part MultipartBody.Part </b> */ @POST("/form") @Multipart Call<ResponseBody> testFileUpload2(@PartMap Map<String, RequestBody> args, @Part MultipartBody.Part file); @POST("/form") @Multipart Call<ResponseBody> testFileUpload3(@PartMap Map<String, RequestBody> args); } public static void main(String[] args) { Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost:4567/") .build(); BlogService service = retrofit.create(BlogService.class); // 演示 @FormUrlEncoded 和 @Field Call<ResponseBody> call1 = service.testFormUrlEncoded1("怪盗kidou", 24); ResponseBodyPrinter.printResponseBody(call1); //=================================================== // 演示 @FormUrlEncoded 和 @FieldMap // 实现的效果与上面想同 Map<String, Object> map = new HashMap<>(); map.put("username", "怪盗kidou"); map.put("age", 24); Call<ResponseBody> call2 = service.testFormUrlEncoded2(map); ResponseBodyPrinter.printResponseBody(call2); //=================================================== MediaType textType = MediaType.parse("text/plain"); RequestBody name = RequestBody.create(textType, "怪盗kidou"); RequestBody age = RequestBody.create(textType, "24"); RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "这里是模拟文件的内容"); // 演示 @Multipart 和 @Part MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file); Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart); ResponseBodyPrinter.printResponseBody(call3); //=================================================== // 演示 @Multipart 和 @PartMap // 实现和上面同样的效果 Map<String, RequestBody> fileUpload2Args = new HashMap<>(); fileUpload2Args.put("name", name); fileUpload2Args.put("age", age); //这里并不会被当成文件,因为没有文件名(包含在Content-Disposition请求头中),但上面的 filePart 有 //fileUpload2Args.put("file", file); Call<ResponseBody> call4 = service.testFileUpload2(fileUpload2Args, filePart); //单独处理文件 ResponseBodyPrinter.printResponseBody(call4); //=================================================== // 还有一种比较hack的方式可以实现文件上传, // 上面说过被当成文件上传的必要条件就是 Content-Disposition 请求头中必须要有 filename="xxx" 才会被当成文件 // 所有我们在写文件名的时候可以拼把 filename="XXX" 也拼接上去, // 即文件名变成 表单键名"; filename="文件名 (两端的引号会自动加,所以这里不加)也可以实现,但是不推荐方式 Map<String, RequestBody> fileUpload3Args = new HashMap<>(); fileUpload3Args.put("name",name); fileUpload3Args.put("age",age); fileUpload3Args.put("file\"; filename=\"test.txt",file); Call<ResponseBody> testFileUpload3 = service.testFileUpload3(fileUpload3Args); ResponseBodyPrinter.printResponseBody(testFileUpload3); }
参数类
{占位符}和PATH尽量只用在URL的path部分,url中的参数使用Query和QueryMap 代替,保证接口定义的简洁Query、Field和Part这三者都支持数组和实现了Iterable接口的类型,如List,Set等,方便向后台传递数组。demo:Call<ResponseBody> foo(@Query("ids[]") List<Integer> ids);//结果:ids[]=0&ids[]=1&ids[]=2
RxJava和CallAdapter
Converter是对于Call<T>中T的转换,而CallAdapter则可以对Call转换;
导包
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
public interface MallAPI { //将api接口中返回的类型从Call<T>改成Observable<T>,注意不要导成database的包 @FormUrlEncoded @POST("login") Observable<ResponseBody> login2(@FieldMap Map<String, String> map);}
Retrofit retrofit3 = new Retrofit.Builder() .client(client) .baseUrl("url") .addConverterFactory(GsonConverterFactory.create()) //添加calladapter支持 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); MallAPI mallAPI2 = retrofit3.create(MallAPI.class); //RxJava走起 Observable<ResponseBody> responseBodyObservable = mallAPI2.login2(map); responseBodyObservable .subscribeOn(Schedulers.newThread()) .subscribe(new Consumer<ResponseBody>() { @Override public void accept(ResponseBody responseBody) throws Exception { Log.v("meee",getClass()+":\n"+"responseBody:"+responseBody.string()); } });
Retrofit的Url组合规则
公式:BaseUrl + URL有关的注解中的内容 = 组合结果"http://localhost:4567/path/to/other/" + "/post" = "http://localhost:4567/post""http://localhost:4567/path/to/other/" + "post" = "http://localhost:4567/path/to/other/post""http://localhost:4567/post" + "https://github.com/ikidou"="https://github.com/ikidou"
小技巧
在取得结果的地方可以添加public interface MallAPI { @FormUrlEncoded @POST("login") Observable<User> login2(@FieldMap Map<String, String> map);}可以改成public interface MallAPI { @FormUrlEncoded @POST("login") Observable<Response<User>> login2(@FieldMap Map<String, String> map);}
阅读全文
0 0
- Retrofit入门
- retrofit入门
- Retrofit入门
- Retrofit入门
- #Retrofit 入门--Part 1
- Retrofit 入门--part2
- Retrofit基础入门(1)
- Retrofit使用入门
- Retrofit 入门和提高
- Retrofit学习入门
- Retrofit网络请求入门
- Retrofit入门学习
- Retrofit简单入门
- Retrofit 入门篇
- Retrofit简单入门
- Retrofit 的初级入门
- Andriod retrofit 入门
- Retrofit使用入门
- 自理解Https原理:证书传递,握手信息传递,数据加密解密的分析。
- Android RecoverSystem 类
- Binder驱动研究
- 8大内部排序算法学习笔记--(4)归并、基数排序 Java实现
- Linux vi/vim
- Retrofit入门
- jar包,(爬虫用,主要包括httpclient,json,log4j等)
- 有赞微商城如何配置打印机(教程)
- 前端框架vue.js系列(11):元素动画过渡效果
- 【Python初学笔记】no.3 练习-实现linux下的差异备份
- Two Sum
- 2017年最新互联网行业薪资报告,云计算和大数据最高
- Android启动模式分析
- IT如何转为销售