《Android第一行代码 第三版》Retrofit的使用 java代码

Retrofit (第三版)

Retrofit就是Square公司在OkHttp的基础上进一步开发出来的应用层网络通信技术,使得我们可以用更加面向对象的思维进行网络操作。

Retrofit项目主页

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类型,并通过泛型来指定服务器相应的数据应该转换成什么对象
    // 这里传递的是请求地址的相对路径,根路径会在后面设置
}

基本使用

步骤:

  1. 首先使用Retrofit.Builder来构建一个Retrofit对象;

  2. 调用retrofit对象的create()方法,并传入具体Service接口的Class类型,创建一个该接口的动态代理对象;

  3. 通过这个接口代理对象使用接口中的方法。

    <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 注解_顾缘君兮的博客-CSDN博客

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);//获取接口的代理对象

这里和书上写的不太一样,书上的没太看懂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值