这是我参与「第四届青训营 」笔记创作活动的第2天。今天学习的内容是android的数据存储和网络通信。
数据存储
数据持久化也是广泛常见的重要需求,不用应用场景使用的存储方法也不同。
四大存储方式
| 存储方式 | 特点 | 使用场景 |
|---|---|---|
| SharedPreferences | 用键值对存boolean\int\floar\ong\String | 记录app信息 |
| 文件 | 文件格式不限,不能跨app共享 | 下载的资源文件 |
| ContentProvider | 跨app共享,通过url对下访问 | 读写音视频图片通讯录 |
| SQLite | 存储结构化数据,方便curd | feed流,curd |
room
room是google出的基于room的数据库框架
room的三个主要组件
Database:保存、连接数据的访问点
Entity:数据库的表
Dao:数据访问对象,提供curd的method
接入room
去官网抄依赖添加到项目中,但是要注意注解处理的依赖,因为kotlin和java用的不同。
room的使用
创建Entity
@Entity
data class User(
@PrimaryKey(autoGenerate = true) val uid: Int?,
@ColumnInfo(name = "name") var name: String?,
)
创建一个data class,添加@Entity注解,class的成员变量是表信息,一个实例代表数据库表的一个记录
创建DAO
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll() : List<User>?
@Query("SELECT * FROM user WHERE uid IN(:userIds)")
fun loadAllByIds(userIds : IntArray): List<User>?
}
创建一个interface,添加@Dao注解,接口方法为具体业务,方法添加相关注解,注解内容为SQL语句。
创建数据库
@Database(entities = [User::class], version = 1)
abstract class UserDataBase : RoomDatabase() {
abstract fun userDao(): UserDao
}
创建一个抽象类,继承自RoomDatabase,抽象类应有一个抽象方法,方法返回一个Dao实例。
创建数据库实例
val db = Room.databaseBuilder(this,UserDataBase::class.java,"userDataBase").build()
使用room的工厂方法构造数据库实例,当然这应该是单例的。
然后通过之前的抽象方法获取dao,就可以通过dao去curd了。
room的原理
1、kapt注解处理:在编译器通过kapt处理@Dao和Database注解生成其实现类,后者实现类有用于创建创建Database的supportopenhelper的createopenhelper方法,前者则持有roomDatabase、EntityinsertionAdapterd(用于数据inset)、entityDeletionOrUpdateAdapter(用于数据update和delete)的实例。剩下的内容则是我们接口的实现,使用db实例开启事务,使用剩下的实例完成业务。
网络存储
okhttp简单使用
先简单回顾下okhttp的一个流程,首先我们需要构造一个OkHttpClient,通过Request的工厂方法构造一个request实例,然后通过client实例的newCall方法传入request构造call,将call请求入队,然后添加结果回调,如果成功,则接收response的body数据(仅此一次,然后respon就会关闭),然后切线程。
class MainActivity : AppCompatActivity() {
var mClient: OkHttpClient = OkHttpClient()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val url = "xxx"
val request: Request = Request.Builder().url(url).build()
val call: Call = mClient.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
//寄
}
override fun onResponse(call: Call, response: Response) {
val result = response.body?.string()
runOnUiThread {
Runnable { //更新UI } }
}
}
}
})
}
}
call的构造
call的构造交由RealCall的newRealCall方法完成,他给Call添加了一个Transmitter。
call的入队
enqueue方法中,Transmitter回调了listener,方法用AsyncCall封装Callback,然后由client分发入队。
AsyncCall内容
AsyncCall是一个Runnable,run方法里调用execute,execute里调用拦截器链处理,最后获取结果并回调,如果寄了就通过异常抛出,回调。最终不管结果如何,都会由client分发结束这次网络请求
AsyncCall里有个原子计数器volatile AtomicInteger callsPerHost会统计主机会话数量
enqueue方法中,后面调用了promoteAndExecute方法,方法收集了所有可以执行的AsyncCall,AsyncCall会被添加到readyAsyncCalls双向队列中,然后遍历他,寻找符合条件的请求,加入到一个保存有效请求的列表executableCalls和正在执行队列runningAsyncCalls中,而这个筛选条件主要有两条:并发执行的请求数要小于最大的请求数64;某个主机的并发请求数不能超过最大请求数5。然后再遍历执行有效网络请求,通过executeOn方法执行,执行参数需要一个连接池。创建连接池使用executorService方法。