数据存储&网络通信
这是我参与「第四届青训营 」笔记创作活动的的第3天
概要
-
网络通信(开源库对比、Retrofit、TTNET)
-
数据存储(方式对比、框架对比、Room)
网络通信
网络开源库对比
| 请求方式 | 作者 | 包体积 增量 | 使用 成本 | 特点 | 使用场景 |
|---|---|---|---|---|---|
| HttpURL Connection | Android sdk OKB | 0KB | 2n | 需要自己做封装,例如线程池管理、返回的数据解析 | 只有少量网络请求的 工具类App |
| Volley | 57KB | n | 1.适合网络请求频繁,传输数据量小 2.不适合用来上传文件和下载 3. 已停更 | 之前使用volley,且 无需大文件下载的App | |
| OkHttp | square公司 | 262KB | 1.5n | 1.可以设置拦截器,支持大文件上传和下载 2.OkHttp 基于NIO和 Okio,性能更好 3. 一般需要二次封装使用 | 一般比较少直接使用, 可搭配Volley或Retrofit |
| Retrofit | square公司 | 343KB | 2n | 具备OkHttp所有的优点,且更出色 1. restful api设计风格 2.通过注解配置请求,包括请求方法、请求参数、请求头、返回值等 3.可以搭配多种Converter将获得的数据解析,支持Gson、 jackson、Protobur等 | 团队内有研发人员对 Retrofit比较熟悉时可使用 |
Retrofit
Retrofit是对OkHttp的一个封装框架,是目前最流行的网络请求框架。
- 引入依赖
dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
//...其他依赖
}
- 创建用于 描述网络请求的接口
//接口类名:可自定义,尽量和这类请求的含义相关
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就好。
- 调用接口发起网络请求
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
网络通信总结
数据存储
数据存储方式对比
| 存储方式 | 特点 | 使用场景 |
|---|---|---|
| SharedPreferences | 1.只能存boolean、 int、 float、 long、 String 5种简单类型 2. 键值对存储 | 记录app的各种配置信息,例如用户自 己切换的开关、服务端下发的某个配置等 |
| 文件存储 | 1.可以存各种格式的文件到手机中 2.默认情况下文件不能跨app共享 | 1.网络下载的zip包 2.txt文件的存储 |
| ContentProvider | 1.可跨App进行数据共享 2.通过Uri对下进行访问 | 1.音频、视频、图片、通信录的读写 |
| SQLite存储数据 | 1.可存储结构化数据 2.对数据进行增删改查较为方便 | 1.保存feed流数据,并进行增删改查 |
数据库框架对比
| 数据库 | 包增量 | 性能对比 | 使用成本 | 支持多表 联合查询 | 支持 LiveData、协程 | 支持数据 库加密 | 作者 |
|---|---|---|---|---|---|---|---|
| Room | 165KB | n | n | Yes | Yes | Yes | |
| GreenDao | 151KB | 0.5n | n | Yes | No | Yes | 三方 |
| ObjectBox | 1879KB | 0.3n | 0.6n | No | No | No | 三方 |
Room
Room是 Google Jetpack 家族里的一员,在SQLite上提供了一个抽象层,以便流畅使用,
主要的3个组件:
-
Database:用于保存数据库并作为应用持久性数据底层连接的主要访问点。 -
Entity:用于表示应用的数据库中的表。 -
DAO:提供应用可用于查询、更新、插入和删除数据库中的数据的方法。
基本使用:
- 加入依赖
dependencies {
def room_version = "2.4.2"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
// ...其他依赖
}
- 数据库表设计
- 新建Entity(属性与数据库表字段一一对应)
- 新建DAO(使用SQL注解进行增删改查)
- 新建数据库类(与entity和dao关联)
- 通过数据库类获取dao对象
Room核心原理:
- 编译期,通过kapt处理
@Dao、@Database注解,动态生成对应的实现类- 生成DAO和Database的实现类
AppDatabase-->AppDatabase_ImplUserDao-->UserDao_Impl
- 生成DAO和Database的实现类
- 底层使用Android提供的
SupportSQLiteOpenHelper实现数据库的增删改查等操作Room.databaseBuilder().build()创建Database时,会调用实现类的createOpenHelper()创建SupportSQLiteOpenHelper,此Helper用来创建DB以及管理版本