Retrofit2 完全解析 探索与okhttp之间的关系,面试Android岗

本文深入剖析了Retrofit2与Okhttp的关系,讲解了如何使用Retrofit2进行HTTP请求,包括查询参数、POST请求、文件上传下载等。文章还探讨了Retrofit2如何为接口生成实例,以及整体执行流程,揭示了其内部动态代理机制。此外,文中提到了自定义Converter.Factory的重要性,并讨论了面试中可能遇到的Retrofit2相关问题。
摘要由CSDN通过智能技术生成

//用于访问zhy的信息

http://192.168.1.102:8080/springmvc_users/user/zhy

//用于访问lmj的信息

http://192.168.1.102:8080/springmvc_users/user/lmj

即通过不同的username访问不同用户的信息,返回数据为json字符串。

那么可以通过retrofit提供的@PATH注解非常方便的完成上述需求。

我们再定义一个方法:

public interface IUserBiz

{

@GET(“{username}”)

Call getUser(@Path(“username”) String username);

}

可以看到我们定义了一个getUser方法,方法接收一个username参数,并且我们的@GET注解中使用{username}声明了访问路径,这里你可以把{username}当做占位符,而实际运行中会通过@PATH("username")所标注的参数进行替换。

那么访问的代码很类似:

//省略了retrofit的构建代码

Call call = userBiz.getUser(“zhy”);

//Call call = userBiz.getUser(“lmj”);

call.enqueue(new Callback()

{

@Override

public void onResponse(Call call, Response response)

{

Log.e(TAG, “getUsePath:” + response.body());

}

@Override

public void onFailure(Call call, Throwable t)

{

}

});

(3)查询参数的设置@Query

看下面的url

http://baseurl/users?sortby=username

http://baseurl/users?sortby=id

即一般的传参,我们可以通过@Query注解方便的完成,我们再次在接口中添加一个方法:

public interface IUserBiz

{

@GET(“users”)

Call<List> getUsersBySort(@Query(“sortby”) String sort);

}

访问的代码,其实没什么写的:

//省略retrofit的构建代码

Call<List> call = userBiz.getUsersBySort(“username”);

//Call<List> call = userBiz.getUsersBySort(“id”);

//省略call执行相关代码

ok,这样我们就完成了参数的指定,当然相同的方式也适用于POST,只需要把注解修改为@POST即可。

对了,我能刚才学了@PATH,那么会不会有这样尝试的冲动,对于刚才的需求,我们这么写:

@GET(“users?sortby={sortby}”)

Call<List> getUsersBySort(@Path(“sortby”) String sort);

乍一看别说好像有点感觉,哈,实际上运行是不支持的~估计是@ Path的定位就是用于url的路径而不是参数,对于参数还是选择通过@Query来设置。

(4)POST请求体的方式向服务器传入json字符串@Body

大家都清楚,我们app很多时候跟服务器通信,会选择直接使用POST方式将json字符串作为请求体发送到服务器,那么我们看看这个需求使用retrofit该如何实现。

再次添加一个方法:

public interface IUserBiz

{

@POST(“add”)

Call<List> addUser(@Body User user);

}

提交的代码其实基本都是一致的:

//省略retrofit的构建代码

Call<List> call = userBiz.addUser(new User(1001, “jj”, “123,”, “jj123”, “jj@qq.com”));

//省略call执行相关代码

ok,可以看到其实就是使用@Body这个注解标识我们的参数对象即可,那么这里需要考虑一个问题,retrofit是如何将user对象转化为字符串呢?下文将详细解释~

下面对应okhttp,还有两种requestBody,一个是FormBody,一个是MultipartBody,前者以表单的方式传递简单的键值对,后者以POST表单的方式上传文件可以携带参数,retrofit也二者也有对应的注解,下面继续~

(5)表单的方式传递键值对@FormUrlEncoded

这里我们模拟一个登录的方法,添加一个方法:

public interface IUserBiz

{

@POST(“login”)

@FormUrlEncoded

Call login(@Field(“username”) String username, @Field(“password”) String password);

}

访问的代码:

//省略retrofit的构建代码

Call call = userBiz.login(“zhy”, “123”);

//省略call执行相关代码

ok,看起来也很简单,通过@POST指明url,添加FormUrlEncoded,然后通过@Field添加参数即可。

(6)单文件上传@Multipart

下面看一下单文件上传,依然是再次添加个方法:

public interface IUserBiz

{

@Multipart

@POST(“register”)

Call registerUser(@Part MultipartBody.Part photo, @Part(“username”) RequestBody username, @Part(“password”) RequestBody password);

}

这里@MultiPart的意思就是允许多个@Part了,我们这里使用了3个@Part,第一个我们准备上传个文件,使用了MultipartBody.Part类型,其余两个均为简单的键值对。

使用:

File file = new File(Environment.getExternalStorageDirectory(), “icon.png”);

RequestBody photoRequestBody = RequestBody.create(MediaType.parse(“image/png”), file);

MultipartBody.Part photo = MultipartBody.Part.createFormData(“photos”, “icon.png”, photoRequestBody);

Call call = userBiz.registerUser(photo, RequestBody.create(null, “abc”), RequestBody.create(null, “123”));

ok,这里感觉略为麻烦。不过还是蛮好理解~~多个@Part,每个Part对应一个RequestBody。

这里插个实验过程,其实我最初对于文件,也是尝试的@Part RequestBody,因为@Part("key"),然后传入一个代表文件的RequestBody,我觉得更加容易理解,后来发现试验无法成功,而且查了下issue,给出了一个很奇怪的解决方案,这里可以参考:retrofit#1063

给出了一个类似如下的方案:

public interface ApiInterface {

@Multipart

@POST (“/api/Accounts/editaccount”)

Call editUser (@Header(“Authorization”) String authorization, @Part(“file”; filename=“pp.png”) RequestBody file , @Part(“FirstName”) RequestBody fname, @Part(“Id”) RequestBody id);

}

可以看到对于文件的那个@Partvalue竟然写了这么多奇怪的东西,而且filename竟然硬编码了~~这个不好吧,我上传的文件名竟然不能动态指定。

为了文件名不会被写死,所以给出了最上面的上传单文件的方法,ps:上面这个方案经测试也是可以上传成功的。

恩,这个奇怪方案,为什么这么做可行,下文会给出非常详细的解释。

最后看下多文件上传~

(7)多文件上传@PartMap

再添加一个方法~~~

public interface IUserBiz

{

@Multipart

@POST(“register”)

Call registerUser(@PartMap Map<String, RequestBody> params, @Part(“password”) RequestBody password);

}

这里使用了一个新的注解@PartMap,这个注解用于标识一个Map,Map的key为String类型,代表上传的键值对的key(与服务器接受的key对应),value即为RequestBody,有点类似@Part的封装版本。

执行的代码:

File file = new File(Environment.getExternalStorageDirectory(), “messenger_01.png”);

RequestBody photo = RequestBody.create(MediaType.parse(“image/png”, file);

Map<String,RequestBody> photos = new HashMap<>();

photos.put(“photos”; filename=“icon.png”, photo);

photos.put(“username”, RequestBo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值