数据存储&网络通信 | 青训营笔记

129 阅读5分钟

数据存储&网络通信

这是我参与「第四届青训营 」笔记创作活动的的第3天

概要

  • 网络通信(开源库对比、Retrofit、TTNET)

  • 数据存储(方式对比、框架对比、Room)

网络通信

网络开源库对比

请求方式作者包体积 增量使用 成本特点使用场景
HttpURL ConnectionAndroid sdk OKB0KB2n需要自己做封装,例如线程池管理、返回的数据解析只有少量网络请求的 工具类App
VolleyGoogle57KBn1.适合网络请求频繁,传输数据量小 2.不适合用来上传文件和下载 3. 已停更之前使用volley,且 无需大文件下载的App
OkHttpsquare公司262KB1.5n1.可以设置拦截器,支持大文件上传和下载 2.OkHttp 基于NIO和 Okio,性能更好 3. 一般需要二次封装使用一般比较少直接使用, 可搭配Volley或Retrofit
Retrofitsquare公司343KB2n具备OkHttp所有的优点,且更出色 1. restful api设计风格 2.通过注解配置请求,包括请求方法、请求参数、请求头、返回值等 3.可以搭配多种Converter将获得的数据解析,支持Gson、 jackson、Protobur等团队内有研发人员对 Retrofit比较熟悉时可使用

Retrofit

Retrofit是对OkHttp的一个封装框架,是目前最流行的网络请求框架。

  1. 引入依赖
dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    //...其他依赖
}
  1. 创建用于 描述网络请求的接口
//接口类名:可自定义,尽量和这类请求的含义相关
interface IUserInfoService {

    @GET("users/{uid}/name")
    fun getUserName(@Path("uid") uid: Int): Call<ResponseBody>

    //@GET("users/{name}/uid")
    //fun getRequest(@Path("name" name:String)) Call<User>
    
    //后续可以增加其他的接口,一个接口对应一个api请求
}

//函数名:可自定义,需要能识别出该接口的作用,该interface里可以增加多个不同的函数
//@GET 注解:用于指定该接口的相对路径,并采用Get方法发起请求
//@Path 注解:需要外部调用时,传入一个uid,该uid会替换@GET注解里相对路径的{uid}
//返回值Call<ResponseBody>,这里用ResponseBody,我们可以直接拿到请求的String内容
//如果要自动转为Model类,例如User,这里直接替换为User就好。
  1. 调用接口发起网络请求
fun getUserName(view: View) {
    //创建Retrofit实例
    val retrofit = Retrofit.Builder()
        .baseUrl("https://www.bytedance.com/")
        .build()
    //创建iUserInfoService实例
    val iUserInfoService = retrofit.create(IUserInfoService::class.java)
    //创建网络请求Call对象
    val call = iUserInfoService.getUserName(1123)
    //发起异步请求
    call.enqueue(object : Callback<ResponseBody> {

        override fun onResponse(call: Call<ResponseBody>,
                                response: Response<ResponseBody>) {
            //请求成功时回调
            request_result_tv.text = "请求成功:" + response.body()!!.string()
        }

        override fun onFailure(call: Call<ResponseBody>, e: Throwable) {
            //请求失败时候的回调
            request_result_tv.text = "请求失败:" + e.message
        }
    })
}

TTNET

TTNet是字节跳动通用的网络请求封装框架。

优点:

  • 基于Retrofit改造,具备了Retrofit所具有的优点
  • 支持多个Http网络库的动态切换(okhttp和cronet)
  • 支持网络拦截配置:添加公共参数,动态切换协议及Host,动态选路等
  • 支持流解析,json序列化

TTNET如何改造Retrofit底层为cronet?

Retrofit在运行期间,配合Java动态代理,获取方法和参数的注解,并构造Request对象。

Retrofit的Builder构造行中,如果未指定callFactory,则会自动创建一个OkHttpClient,创建好的OkHttpClient将会保存在Retrofit实例中。当我们通过代理对象调用我们的接口方法时,会触发InvocationHandler#invoke方法,在这个方法中,Retrofit写死了只支持OkHttp。

所以核心主要是替换其中用到的:1. OkHttpClient 2. OkHttpCall

网络通信总结

数据存储

数据存储方式对比

存储方式特点使用场景
SharedPreferences1.只能存boolean、 int、 float、 long、 String 5种简单类型 2. 键值对存储记录app的各种配置信息,例如用户自 己切换的开关、服务端下发的某个配置等
文件存储1.可以存各种格式的文件到手机中 2.默认情况下文件不能跨app共享1.网络下载的zip包 2.txt文件的存储
ContentProvider1.可跨App进行数据共享 2.通过Uri对下进行访问1.音频、视频、图片、通信录的读写
SQLite存储数据1.可存储结构化数据 2.对数据进行增删改查较为方便1.保存feed流数据,并进行增删改查

数据库框架对比

数据库包增量性能对比使用成本支持多表 联合查询支持 LiveData、协程支持数据 库加密作者
Room165KBnnYesYesYesGoogle
GreenDao151KB0.5nnYesNoYes三方
ObjectBox1879KB0.3n0.6nNoNoNo三方

Room

Room是 Google Jetpack 家族里的一员,在SQLite上提供了一个抽象层,以便流畅使用,

主要的3个组件:

  • Database:用于保存数据库并作为应用持久性数据底层连接的主要访问点。

  • Entity:用于表示应用的数据库中的表。

  • DAO:提供应用可用于查询、更新、插入和删除数据库中的数据的方法。

基本使用:

  1. 加入依赖
dependencies {
    def room_version = "2.4.2"
    implementation "androidx.room:room-runtime:$room_version" 
    kapt "androidx.room:room-compiler:$room_version"
    // ...其他依赖
}
  1. 数据库表设计
  2. 新建Entity(属性与数据库表字段一一对应)
  3. 新建DAO(使用SQL注解进行增删改查)
  4. 新建数据库类(与entity和dao关联)
  5. 通过数据库类获取dao对象

Room核心原理:

  1. 编译期,通过kapt处理@Dao@Database注解,动态生成对应的实现类
    • 生成DAO和Database的实现类 AppDatabase --> AppDatabase_Impl UserDao-->UserDao_Impl
  2. 底层使用Android提供的SupportSQLiteOpenHelper实现数据库的增删改查等操作
    • Room.databaseBuilder().build()创建Database时,会调用实现类的 createOpenHelper()创建SupportSQLiteOpenHelper,此Helper用来创建DB以及管理版本

数据存储总结