Retrofit (第三版)
Retrofit就是Square公司在OkHttp的基础上进一步开发出来的应用层网络通信技术,使得我们可以用更加面向对象的思维进行网络操作。
Retrofit的基本用法
Retrofit的设计思想
-
首先配置好一个根路径,然后再指定服务器接口地址时只需要使用相对路径即可。这样就不用每次都指定完整的URL地址了。
-
允许我们对服务器接口进行归类,将功能同属一类的服务器接口定义到同一个接口文件中,从而让代码结构变得更加合理。
-
不用关心网络通信细节,只需要在接口文件中声明一系列方法和返回值,然后通过注解的方式对应哪个服务器接口,以及需要提供的参数。
导依赖包
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
导第一个包会将Retrofit、OkHttp和Okio这几个库一起下载,因此无需手动引入OkHttp库。另外,Retrofit还会将服务器返回的GSON数据自动解析成对象。因此第二条依赖就是一个Retrofit的转换库,他是借助GSON来解析JSON数据的,所以会将GSON库一起下载下来。只需要导入这两个包就足够了。
定义接口
定义接口之前我们呢先新增一个App类,用于接收转化的JSON数据。
public class App {
private String id;
private String name;
private String version;
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
}
定义接口:
import java.util.List;
import retrofit2.Call;//这里注意导的一定是retrofit2的Call包,而不是别的包下的Call包
import retrofit2.http.GET;
public interface AppService {
@GET("get_data.json")
Call<List<App>> getAppData();
//一. @Get注解,表示当调用getAppData()方法时Retrofit会发起一条Get的请求,
// 请求的地址就是我们在@Get注解中传入的具体参数。
//二. getAppData()方法的返回值必须声明称Retrofit中内置的Call类型,并通过泛型来指定服务器相应的数据应该转换成什么对象
// 这里传递的是请求地址的相对路径,根路径会在后面设置
}
基本使用
步骤:
-
首先使用Retrofit.Builder来构建一个Retrofit对象;
-
调用retrofit对象的create()方法,并传入具体Service接口的Class类型,创建一个该接口的动态代理对象;
-
通过这个接口代理对象使用接口中的方法。
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/getAppDataBtn"
android:text="Get App Data" />
//首先在activity_main.xml文件中定义一个按钮
public class MainActivity extends AppCompatActivity {
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.getAppDataBtn).setOnClickListener(view -> {
//1.首先使用Retrofit.Builder来构建一个Retrofit对象
/*
其中baseUrl()方法用于指定所有Retrofit请求的 根路径;
addConverterFactory()方法用于指定Retrofit在解析数据是所使用的转换库,这里使用GSONConverterFactory转换库。
注意:这两个方法都是必须要调用的。
*/
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://10.0.2.2") //根路径
.addConverterFactory(GsonConverterFactory.create())
.build();//构建Retrofit实例
//2.调用retrofit对象的create()方法,并传入具体Service接口的Class类型,创建一个该接口的动态代理对象
AppService appService = retrofit.create(AppService.class);
//3.之后我们就可以通过这个接口代理对象使用接口中的方法了。
/*
当调用AppService的getAppData()方法后,返回的是一个Call<List<App>>对象
这时再调用它的enqueue()方法,Retrofit就会根据注解中配置的服务器接口地址去进行网络请求了
enqueue()方法传入的参数是一个实现Callback的匿名内部类
服务器响应的数据会回调到enqueue()方法传入的Callback的实现里。
当发起请求时,Retrofit会在内部自动开启子线程,当数据回调到Callback之后,Retrofit又会自动切换回主线程,整个操作过程中我们不需要考虑线程问题。
在onResponse()方法中,调用response.body()方法会得到Retrofit解析后的对象,也就是List<App>类型的实体数据。
在onFailure()方法中,可以处理从服务器获取数据失败时的逻辑
*/
appService.getAppData().enqueue(new Callback<List<App>>() {
@Override
public void onResponse(Call<List<App>> call, Response<List<App>> response) {
List<App> apps = response.body();
if (apps != null){
for (App app:
apps) {
Log.d("TAG", "id is " + app.getId());
Log.d("TAG", "name is " + app.getName());
Log.d("TAG", "version is " + app.getVersion());
}
}
}
@Override
public void onFailure(Call<List<App>> call, Throwable t) {
Log.d("TAG", "onFailure: " + t.toString());
}
});
});//定义按钮的点击事件
}
}
注意测试之前要在AndroidManifest.xml文件中配置权限:
<uses-permission android:name="android.permission.INTERNET"/>
《Android第一行代码 第三版》书上使用的服务器是在第11章11.3中搭建的,所以这里如果没有搭建服务器应该会报错读不到数据。
处理复杂的接口地址类型
举例定义 数据实体类型Data
public class Data{
private String id;
private String content;
public String getId(){
return id;
}
public String getContent(){
return content;
}
}
-
当接口地址是静态的,不会改变:GET
http://example.com/get_data.json
//在Retrofit中的接口写法
public interface ExampleService{
@GET("get_data.json")
Call<Data> getData();
}
-
当接口地址是动态改变的:GET
http://example.com/<page>/get_data.json
在这个接口中,<page>表示页数,传入不同的页数,服务器返回的数据也会不同。
import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Path; public interface ExampleService { @GET("{page}/get_data.json") //在注解@GET中使用了一个{page}占位符 //然后在getData()方法中添加page参数,并使用@Path("page")注解来声明这个参数 //调用getData()方法发起请求时,Retrofit就会将getData()中接收的参数page替换到{page}的位置 Call<Data> getData(@Path("page")int page); }
使用Retrofit专门提供的另外一种语法:GET http://example.com/get_data.json?u=<user>&t=<token>
带参数的GET请求:?后面连接的是参数部分,=表示连接键值对,多个参数之间用&关联。
public interface ExampleService{
@GET("get_data.json")
Call<Data> getData(@Query("u")String user, @Query("t")String token);
}
HTTP的请求类型
注解类型:
方法注解:@GET @POST @PUT @DELETE @PATH @HEAD @OPTIONS @HTTP
标记注解:@FormUrlEncoded @Multipart @Streaming
参数注解:@Query @QueryMap @Body @Field @FieldMap @Part @PartMap
其他注解:@Path @Header @Headers @Url
Retrofit 注解参数详解retrofit 参数注解赵彦军的博客-CSDN博客
(还没看)
-
GET:用于从服务器获取数据。
-
POST:用于向服务器提交数据。
-
PUT和PATCH:用于修改服务器上的数据。
-
DELETE:用于删除服务器上的数据。
使用相应的注解,就能发送相应的请求。
PUT、POST、PATCH、DELETE这几个请求类型与GET请求不同,他们更多是操作服务器上的数据,他们对于服务器响应的数据并不关心,可以使用ResponseBody,表示Retrofit可以接受任意类型的响应数据,并且不会对响应数据进行解析(不关心或者不需要服务器返回给我们的数据时)。
删除数据
例如:DELETE http://example.xom/data/<id>
public interface ExampleService{
@DELETE("data/{id}")
Call<ResponseBody> deleteData(@Path("id")String id);
}
提交数据 POST http://example.com/data/create {"id":1, "content":"CONTENT"}
提交数据,需要将数据放到HTTP的body部分,借助@Body注解完成
public interface ExampleService{
@POST(data/create)
Call<ResponceBody> createData(@Body Data data);
}
@Body注解会将对象data解析成json格式的数据,并存放到HTTP的body部分,服务器收到请求后会从body中获取并解析data。
指定HTTP的header值
静态指定header值
例如:GET http://example.com/get_data.json User-Agent:okhttp Cache-Control:max-age=0
public interface ExampleService{
@Headers("User-Agent: okhttp", "Cache-ControlL max-age=0")
@GET("get_data.json")
Call<Data> getData();
}
动态指定header值
public interface ExampleService{
@GET("get_data.json")
Call<Data> getData(@Header("User-Agent")String userAgent, @Header("Cache_Control")String cacheControl);
}
参数中获取header的值。
Retrofit构建器的最佳写法
将之前的代码中获取AppService的代理对象的代码优化:
原代码:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://10.0.2.2")
.addConverterFactory(GsonConverterFactory.create())
.build();//构建Retrofit实例
AppService appService = retrofit.create(AppService.class);
因为针对同一根路径的Retrofit对象是全局通用的,需要改变的只是create()方法中传入的接口的class对象。
将这一功能代码封装起来,新建一个ServiceCreate的单例类。
public class ServiceCreate {
private static final String BASE_URL = "http://10.0.0.2";
private static final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
public static Object create(Class serviceClass){
return retrofit.create(serviceClass);
}
}
AppService appService =(AppService) ServiceCreate.create(AppService.class);//获取接口的代理对象
这里和书上写的不太一样,书上的没太看懂。