Retrofit_L

Retrofi 官网  传送门
介绍:
三步走:
1.请求Api写在一个java接口里
public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}
2.Retrofi 实现该Api接口的一个实体类
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();
GitHubService service = retrofit.create(GitHubService.class);
3.同步/异步的请求的回调
Call<List<Repo>> repos = service.listRepos("octocat");
Api 声明
REQEUST METHOD 请求方法
GET,POST,PUT,DELETE,HEAD
例: @GET("users/list")
你也可以指定请求参数在url里
@GET("users/list?sort=desc")


URL MANIPULATION url操作
一个请求url可以通过替换模块和参数进行动态更新。
替换模块是被{}包裹的单词

对应的参数也必须用 @Path 注解相同的单词 

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);

@GET("group/{id}/users")

Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);

对于复杂的请求参数,可以运用Map
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);



REQUEST BODY
一个对象可以通过 @Body 注解作为请求体
@POST("users/new")
Call<User> createUser(@Body User user);



FORM ENCODED AND MULTIPART


Form-encoded data is sent when @FormUrlEncoded is present on the method.
加上这句注解,数据就会按格式编码发送
每个键值对用 @Field 注解,包含name和对象提供的value
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);



Multipart requests are used when @Multipart is present on the method. Parts are declared using the @Part annotation.
多个请求体用 @Multipart 注解;请求体用 @Part注解
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);



HEADER MANIPULATION
@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);


注意这些请求头不会相互覆盖
请求头可以通过 @Header 动态更新,如果value是null,请求头会被忽略。
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)


Headers that need to be added to every request can be specified using an OkHttp interceptor.
如果想把请求头加入每个请求中,可以配置OkHttp的拦截器



SYNCHRONOUS VS. ASYNCHRONOUS
同步/异步
Call 回调同步和异步都可以执行
每个Call的实体对象只能使用一次
但是可以通过clone方法会创建一个同样的实体对象
在Android里,回调会在主线程中执行
在JVM,CallBack 会在和发起请求的同一线程中执行



Retrofit Configuration
retrofit的通常配置
六种支持的转换器
分别是
Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
(Square全家桶)
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build();


GitHubService service = retrofit.create(GitHubService.class);
自定义转换器的话 Create a class that extends the Converter.Factory class
感觉不会用到了


======
注解以及转换器的详细用法

这是一篇很重要很全面可能是我读过的最好的关于Retrofit详解

我记录下比较有用的
标记类
FormUrlEncoded 表单格式 键值对
Multipart       带有文件上传


@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);

示例:
Call<ResponseBody> call1 = service.testFormUrlEncoded1("怪盗kidou", 24);


@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map);

示例:
Map<String, Object> map = new HashMap<>();
map.put("username", "怪盗kidou");
map.put("age", 24);
Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);


=======
Multipart


@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);

示例:
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"), "这里是模拟文件的内容");
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);

Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);


注意这里MediaType解析的协议部分,详见  MIME参考手册
mp3  --- audio/mpeg
zip  --- application/zip
gif  --- image/gif
jpeg --- image/jpeg
html --- text/html
txt  --- text/plain
mpeg --- video/mpeg


@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload2(@PartMap Map<String, RequestBody> args, @Part MultipartBody.Part file);

示例:
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); //单独处理文件


参数类
Headers 用于添加请求头
Header  用于添加不固定值的请求头
Body    用于非表单请求体

Field FieldMap 与FormUrlEncoded配合 用于表单字段
FieldMap接受的类型是Map<String,String>,非String类型会调用其toString方法

Part PartMap 与Multipart配合 适合文件上传
PartMap 默认接受类型是Map<String,RequestBody>,非RequetBody类型会通过Converter转换

Path/Query/QueryMap/Url 用于Url
Query/QueryMap和Field/FieldMap功能是一样的,
只不过分别对应于Url和请求体



示例:
@GET("/headers?showAll=true")
@Headers({"CustomHeader1: customHeaderValue1", "CustomHeader2: customHeaderValue2"})
Call<ResponseBody> testHeader(@Header("CustomHeader3") String customHeaderValue3);


@GET //当有URL注解时,这里的URL就省略了
Call<ResponseBody> testUrlAndQuery(@Url String url, @Query("showAll") boolean showAll);
Call<ResponseBody> call1 = service.testUrlAndQuery("headers",false);


=====先熟悉下Gson的用法======
https://www.jianshu.com/p/e740196225a4
同样,我记录下生疏的部分(通读过后,以前的连皮毛都不是,差不多都要记)
基本用法:
Gson gson = new Gson();
int i = gson.fromJson("100", int.class);              //100
double d = gson.fromJson("\"99.99\"", double.class);  //99.99
boolean b = gson.fromJson("true", boolean.class);     // true
String str = gson.fromJson("String", String.class);   // String


String jsonObject = gson.toJson(user); // {"name":"怪盗kidou","age":24}
User user = gson.fromJson(jsonString, User.class);


Gson中使用泛型
["Android","Java","PHP"]此类字符串数组
数组和List都是候选项
泛型擦除
Gson gson = new Gson();
String jsonArray = "[\"Android\",\"Java\",\"PHP\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());


(注:TypeToken的构造方法是protected修饰的,所以上面才会写成new TypeToken<List<String>>() {}.getType() 而不是  new TypeToken<List<String>>().getType())
了解一下即可,容易记错


泛型解析对接口POJO的设计影响
泛型的引入可以减少无关的代码


比如:
public class UserResponse {
    public int code;
    public String message;
    public User data;
}
当其它接口的时候又重新定义一个XXResponse将data的类型改成XX,
很明显code,和message被重复定义了多次,
通过泛型的话我们可以将code和message字段抽取到一个Result的类中,
这样我们只需要编写data字段所对应的POJO即可,更专注于我们的业务逻辑。如:
public class Result<T> {
    public int code;
    public String message;
    public T data;
}

示例代码:
//不再重复定义Result类
Type userType = new TypeToken<Result<User>>(){}.getType();
Result<User> userResult = gson.fromJson(json,userType);
User user = userResult.data;


Type userListType = new TypeToken<Result<List<User>>>(){}.getType();
Result<List<User>> userListResult = gson.fromJson(json,userListType);
List<User> users = userListResult.data;


!!!属性重命名 @SerializedName 注解的使用
前端期望的json格式:
{"name":"怪盗kidou","age":24,"emailAddress":"ikidou@example.com"}
实际后台给的:
{"name":"怪盗kidou","age":24,"email_address":"ikidou@example.com"}
这对于使用PHP作为后台开发语言时很常见的情况,php和js在命名时一般采用下划线风格,而Java中一般采用的驼峰法,
让后台的哥们改吧 前端和后台都不爽,但要自己使用下划线风格时我会感到不适应,怎么办?难到没有两全齐美的方法么?
我们知道Gson在序列化和反序列化时需要使用反射,
说到反射就不得不想到注解,一般各类库都将注解放到annotations包下,

打开源码在com.google.gson包下果然有一个annotations,里面有一个SerializedName的注解类,这应该就是我们要找的。(写的太好了,全copy了)
@SerializedName("email_address")
public String emailAddress;

更实际的开发场景:
如果接中设计不严谨或者其它地方可以重用该类,其它字段都一样,就emailAddress 字段不一样,比如有下面三种情况那怎么?重新写一个?
为POJO字段提供备选属性名
SerializedName注解提供了两个属性,上面用到了其中一个,别外还有一个属性alternate,接收一个String数组。
注:alternate需要2.4版本
@SerializedName(value = "emailAddress", alternate = {"email", "email_address"})
public String emailAddress;
当上面的三个属性(email_address、email、emailAddress)都中出现任意一个时均可以得到正确的结果。
注:当多种情况同时出时,以最后一个出现的值为准。



=====先熟悉下Gson的用法======
Gson Convert 
https://github.com/ikidou/Retrofit2Demo/blob/master/client/src/main/java/com/github/ikidou/Example06.java
@POST("blog")
Call<Result<Blog>> createBlog(@Body Blog blog);
BlogService service = retrofit.create(BlogService.class);


Blog blog = new Blog();
blog.content = "新建的Blog";
blog.title = "测试";
blog.author = "怪盗kidou";
Call<Result<Blog>> call = service.createBlog(blog);
======


RxJava与CallAdapter


Retrofit retrofit = new Retrofit.Builder()
      .baseUrl("http://localhost:4567/")
      . addConverterFactory( GsonConverterFactory.create())
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
      // 针对rxjava2.x
      . addCallAdapterFactory( RxJava2CallAdapterFactory.create()) 
      .build();


Converter是对于Call<T>中T的转换,而CallAdapter则可以对Call转换


compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
// 针对rxjava2.x(adapter-rxjava2的版本要 >= 2.2.0)
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'


接口设计
public interface BlogService {
  @POST("/blog")
  Observable<Result<List<Blog>>> getBlogs();
}
像上面的这种情况最后我们无法获取到返回的Header和响应码的,如果我们需要这两者,提供两种方案:
1、用Observable<Response<T>> 代替 Observable<T> ,这里的Response指retrofit2.Response
2、用Observable<Result<T>> 代替 Observable<T>,这里的Result是指retrofit2.adapter.rxjava.Result,这个Result中包含了Response的实例



自定义 Converter 和 CallAdapter
Retrofit retrofit = new Retrofit.Builder()
      .baseUrl("http://localhost:4567/")
      // 如是有Gson这类的Converter 一定要放在其它前面
      .addConverterFactory(StringConverterFactory.create())//自定义的StringConverterFactory
      .addConverterFactory(GsonConverterFactory.create())
      .build();
注:addConverterFactory是有先后顺序的,
如果有多个ConverterFactory都支持同一种类型,那么就是只有第一个才会被使用,
而GsonConverterFactory是不判断是否支持的,所以这里交换了顺序还会有一个异常抛出,原因是类型不匹配。

自定义部分详见学习链接吧


====
Retrofit.Builder的client(OkHttpClient)方法
设置自定义的OkHttpClient,以前的Retrofit版本中不同的Retrofit对象共用同OkHttpClient,
在2.0各对象各自持有不同的OkHttpClient实例,所以当你需要共用OkHttpClient或需要自定义时则可以使用该方法,如:处理Cookie、使用stetho 调式等


Retrofit的Url组合规则
如果你在注解中提供的url是完整的url,则url将作为请求的url。
如果你在注解中提供的url是不完整的url,且不以 / 开头,则请求的url为baseUrl+注解中提供的值

如果你在注解中提供的url是不完整的url,且以 / 开头,则请求的url为baseUrl的主机部分+注解中提供的值



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
retrofit_generator是一个用于生成Retrofit代码的工具。它是Retrofit库的一个开发依赖项,用于自动生成网络请求的代码。在Flutter项目中,您可以使用retrofit_generator来生成与Retrofit相关的代码,包括接口定义和网络请求方法。通过在pubspec.yaml文件中添加retrofit_generator作为开发依赖项,并使用build_runner来运行代码生成器,您可以轻松地生成所需的代码。\[2\] #### 引用[.reference_title] - *1* [flutter retrofit集成](https://blog.csdn.net/qq_38373150/article/details/118153802)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Retrofit详解](https://blog.csdn.net/qq_30621333/article/details/115485408)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [soa快速指南_扑扑网络快速指南](https://blog.csdn.net/weixin_26727575/article/details/108497424)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值