『Android基础入门』网络编程之OKHTTP与Retrofit框架

141 阅读8分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

👨‍🎓作者简介:一位喜欢写作,计科专业的大二菜鸟

🏡个人主页:starry陆离

🕒首发日期:2022年7月6日星期三

🌌上期文章:『Android基础入门』网络请求数据与JSON解析

📚订阅专栏:『Android基础入门』 如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦


1. 上期回顾

上一期我们实现了Android的网络编程,通过Java代码在子线程中请求数据,再通过Java代码解析json数据,因为对于较复杂的json数据,通过java代码需要逐层解析比较困难,所以我们又通过第三方框架GSON,使用它可以直接将字符串解析成对象,并且封装成为一个实体类,配合实体类插件GsonFormatPlus,让我们只需通过简单的几行代码就实现数据解析

网络请求-》java-》OKHTTP

数据解析-》java解析-》GSON配合插件解析

网络编程的数据解析部分已经十分的方便了,但网络请求数据部分,通过java代码创建子线程请求到数据,然后又要通过runOnUiThread(new Runnable()方法线程切换到主线程将设数据设置到主线程的控件上,对于开发不便,我们这期学习如何使用OKHTTP框架实现网络请求,解决线程切换的问题

2. 原生HTTP网络访问的缺点

  1. 每次网络访问需要放在子线程里
  2. 每次得到结果需要返回到主线程才能更新控件显示
  3. 需要对各种情况进行处理,没有对状态码判断

3. OKHTTP

概述 - OkHttp (square.github.io)

HTTP是现代应用程序网络的方式。这就是我们交换数据和媒体的方式。有效地执行 HTTP 会使内容加载速度更快并节省带宽。

OkHttp 是一个默认高效的 HTTP 客户端:

  • HTTP/2 支持允许对同一主机的所有请求共享一个套接字。
  • 连接池可减少请求延迟(如果 HTTP/2 不可用)。
  • 透明 GZIP 可缩小下载大小。
  • 响应缓存完全避免了重复请求的网络。

OkHttp 适用于 Android 5.0+(API 级别 21+)和 Java 8+。

3.1 框架引入

框架官网地址

 https://github.com/square/okhttp

添加网络请求权限

image-20220511235948525

添加依赖

 implementation("com.squareup.okhttp3:okhttp:4.9.3")

image-20220512000346633

3.2 框架使用

3.2.1 数据请求

 ​
 public class MainActivity extends AppCompatActivity {
 ​
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
 ​
         //发起请求
         //无需手动创建子线程,框架默认帮我们创建
 ​
         //1.创建一个okhttp对象
         OkHttpClient okHttpClient=new OkHttpClient();
         //2.创建一个Request对象,里面存放请求到的数据,调用Request类里的builder()方法,相当于调用了Request的静态方法
         //.url请求的地址
         //.get() 请求的方式 常用的请求方法1.get()   2.post() 这个由后端的接口决定
         //.build()
         Request request=new Request.Builder()
                 .url("http://121.4.44.56/object")
                 .get()
                 .build();
         //3.将数据放到okHttpClient对象中
         Call call = okHttpClient.newCall(request);
         //enqueue一个队列,程序可以发起多个请求,将这些请求存在队列中一个一个的处理
         call.enqueue(new Callback() {
             @Override
             public void onFailure(@NonNull Call call, @NonNull IOException e) {
                 //请求失败
             }
 ​
             @Override
             public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                 //请求成功,通过response对象返回请求到的数据
                 String result=response.body().string();
                 Log.i("onResponse", "onResponse: "+result);
             }
         });
     }
 }

由此我们可以知道okhttp框架相较于传统的网络请求的优势:

优势一:无需自己创建子线程,okhttp自动帮我们创建

优势二:返回的数据不再是数据流,而是转换好的string字符串

优势三:自动处理异常情况,提供onFailure()方法

打印测试结果:

image-20220512002617352

3.2.2 数据解析

这是返回的数据还是没有经过解析的,我们可以使用上节课的GSON搭配实体类插件GsonFormatPlus来解析数据

第一步:添加gson依赖

   //添加GSON依赖
     implementation 'com.google.code.gson:gson:2.9.0'

image-20220512003426393

第二步:创建实体类

我们可以复制json数据,通过实体类插件GsonFormatPlus快速创建

android9.1

第三步:解析数据

 //GSON搭配实体类插件`GsonFormatPlus`来解析数据
     Gson gson=new Gson();
     Student student=gson.fromJson(result,Student.class);

image-20220512004546140

第四步:设置到文本控件上显示

我们先得给文本控件取一个id,为了方便查看,我设置了文本的大小和颜色

image-20220512004824300

然后将解析出的数据设置到文本控件上

同样的在okhttp中我们需要切换线程到主线程来设置数据到控件上,说明okhttp框架只帮我们解决了构建子线程的问题,线程切换还是需要自己实现

运行可以看到名字已经解析出来并显示在虚拟机上

image-20220512190625102

3.3 MainActivity完整代码

 public class MainActivity extends AppCompatActivity {
 ​
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
 ​
         TextView txtView = findViewById(R.id.txtVId1);
 ​
         //发起请求
         //无需手动创建子线程,框架默认帮我们创建
 ​
         //1.创建一个okhttp对象
         OkHttpClient okHttpClient=new OkHttpClient();
         //2.创建一个Request对象,里面存放请求到的数据,调用Request类里的builder()方法,相当于调用了Request的静态方法
         //.url请求的地址
         //.get() 请求的方式 常用的请求方法1.get()   2.post() 这个由后端的接口决定
         //.build()
         Request request=new Request.Builder()
                 .url("http://121.4.44.56/object")
                 .get()
                 .build();
         //3.将数据放到okHttpClient对象中
         Call call = okHttpClient.newCall(request);
         call.enqueue(new Callback() {//enqueue一个队列,程序可以发起多个请求,将这些请求存在队列中一个一个的处理
             @Override
             public void onFailure(@NonNull Call call, @NonNull IOException e) {
                 //请求失败,打印解析失败原因
                 Log.i("onFailure", "onFailure: "+e.getMessage());
             }
 ​
             @Override
             public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                 //请求成功,通过response对象返回请求到的数据
                 //子线程
                 String result=response.body().string();
                 Log.i("onResponse", "onResponse: "+result);
 ​
                 //GSON搭配实体类插件`GsonFormatPlus`来解析数据
                 Gson gson=new Gson();
                 Student student=gson.fromJson(result,Student.class);
                 //抛出到主线程
                 runOnUiThread(new Runnable() {
                       @Override
                       public void run() {
                           txtView.setText(student.name);
                       }
                   }
                 );
 ​
             }
         });
 ​
         //优势一:无需自己创建子线程
         //优势二:返回的数据不再是数据流,而是转换好的string字符串
         //优势三:自动处理异常情况,提供`onFailure()`方法
     }
 }

4. 在线接口

1.介绍 · fastmock教程 (gitee.io)

fastmock可以让你在没有后端程序的情况下能真实地在线模拟ajax请求,你可以用fatmock实现项目初期纯前端的效果演示,也可以用fastmock实现开发中的数据模拟从而实现前后端分离。

5. Retrofit

网络请求-》java-》OKHTTP-》Retrofit

数据解析-》java解析-》GSON配合插件解析

Retrofit是对http网络请求框架的封装,一般由okhttp来负责网络请求,retrofit对请求接口 进行封装。retrofit通过接口和注解来描述我们的网络请求,然后通过client去调用okhttp 框架,通过addConverterFactory来实现对返回的json数据进行处理,转换成我们需要的数 据类型,可以理解为okhttp的加强版,底层封装了Okhttp

5.1 框架引入

     //添加okhttp依赖/
     implementation("com.squareup.okhttp3:okhttp:4.9.3")
     //添加Retrofit依赖
     implementation 'com.squareup.retrofit2:retrofit:2.9.0'
     implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

image-20220512195435853

5.2 框架使用

5.2.1 创建接口

创建一个接口,返回值是Call类型,使用泛型封装Student类,注意引入包不要用okhttp的

image-20220512195933489

 import retrofit2.Call;
 import retrofit2.http.GET;
 ​
 public interface Api {
     //http://121.4.44.56/object
     //使用get注解,放入请求的地址的最后一部分,前面的部分会在别处拼接
     @GET("object")
     Call<Student> getStudent();
 }
 ​

5.2.2 数据请求&数据解析

回到MainActivity方法,将之前写的用okhttp框架的所有代码注释,以及删除对于的所有包

使用Retrofit框架来实现同样的功能

值得注意的是Retrofit框架在okhttp的基础上进一步封装,我们无需手动解析数据,也无需抛出线程

 //使用Retrofit框架
 //1..创建一个Retrofit对象
 Retrofit retrofit=new Retrofit.Builder()
     .baseUrl("http://121.4.44.56/")
     .addConverterFactory(GsonConverterFactory.create())//表示以GSON框架解析数据
     .build();
 ​
 //2.获取到Api接口
 //返回一个接口实例
 Api api = retrofit.create(Api.class);
 ​
 //3.通过Api获取到实体类Student
 retrofit2.Call<Student> call=api.getStudent();
 ​
 //4.enqueue一个队列,程序可以发起多个请求,将这些请求存在队列中一个一个的处理
 call.enqueue(new Callback<Student>() {
     @Override
     public void onResponse(Call<Student> call, Response<Student> response) {
         //请求成功:返回的结果是一个call对象,而不再是response,
         //默认将请求的结果抛回到主线程
         Student student = response.body();
         txtView.setText(student.name);
     }
 ​
     @Override
     public void onFailure(Call<Student> call, Throwable t) {
         //请求失败
     }
 });

5.2.3 日志拦截(Retrofit优化)

Retrofit框架看上去已经很完美了,但是因为它帮我们完成了数据解析,我们无法捕获数据解析是否成功,所以当数据解析失败时通过response.body();是获取不到数据的

面对这个问题同样也有解决办法

我们引入一下依赖

 //拦截日志依赖
 implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'

image-20220512203216828

通过如下工具类进行拦截,使用这个工具类我们通过日志过滤的方法查看请求的状态和数据解析是否成功

 ​
 public class RetrofitUtils {
 ​
     public static Retrofit getRetrofit(String url) {
         //日志显示级别
         HttpLoggingInterceptor.Level level= HttpLoggingInterceptor.Level.BODY;
         //新建log拦截器
         HttpLoggingInterceptor loggingInterceptor=new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
             @Override
             public void log(String message) {
                 Log.d("RetrofitMessage","OkHttp====Message:"+message);
             }
         });
         loggingInterceptor.setLevel(level);
         //定制OkHttp
         OkHttpClient.Builder httpClientBuilder = new OkHttpClient
                 .Builder();
         //OkHttp进行添加拦截器loggingInterceptor
         httpClientBuilder.addInterceptor(loggingInterceptor);
 ​
         Retrofit retrofit = new Retrofit.Builder()
                 .baseUrl(url)
                 .addConverterFactory(GsonConverterFactory.create())
                 .client( httpClientBuilder.build())
                 .build();
 ​
         return retrofit;
     }
 ​
 }

使用这个工具类也能简化请求数据的代码,我们只需这么一行代码就能拿到Api接口实例

 Api api = RetrofitUtils.getRetrofit("http://121.4.44.56/").create(Api.class);

image-20220512203937551

通过debug级的日志过滤我们可以查看数据请求的状态信息和数据解析结果,也方便我们排错分析

image-20220512204405900

笔记源码

starry陆离/LessonTwo - 码云 - 开源中国 (gitee.com)