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

142 阅读4分钟

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

第四节课 [数据储存 & 网络通信]

网络通信

  • 网络请求框架对比

    • HttpURLConnection:系统自带,小App没太多网络请求时可简单封装使用
    • Volley:事业频繁返回数据体小的App,不适合文件下载,已停更
    • OkHttp:性能好,支持大文件下载,需要封装使用
    • Retrofit:基于OkHttp的封装,有一定门槛 8b894d8d82581bd0e98479c37adb262.jpg

  • Retrofit

    • 介绍:是对OkHttp的一个封装框架

    • 使用

      • Retrofit库的引入: 在build.gradle中

        dependencies {
           impementation 'com.squareup.retrofit2:converter-gson:2.4.0'
        }
        
      • 创建用于描述网络请求的接口

        • 需要加@GET注解:用于指定该接口的相对路径,并采用Get方法发起请求
        • 参数@Path注解:需要外部调用时,传入一个uid,该uid会替换@GET注解中的{uid}
        • 返回值Call<ResponseBody>:可以直接拿到请求的String内容
      • 使用Retrofit实例发起网络请求

        • 创建Retrofit实例
        • 创建请求接口的实例并获取到Call实例
        • 调用call.enqueue进行异步请求
        • 处理返回的数据
    • 原理

      • 使用注解来描述网络请求
      • 通过java同台代理Proxy.newProxyInstance来进行注解的识别和网络请求的构建
      • 底层使用OkHttp发起网络请求
    • Retrofit主流程

      1. 通过Builder模式,创建RetrofitConfig,保存baseUrl等内容
      2. 创建动态代理对象
      3. 创建OkHttpCall
      4. 发起网络请求



  • 注解:

    • 介绍:一个标签,加在类、方法、参数、成员变量上,并且在合适的时机读取注解中的内容进行处理

    • 处理时机

      1. SOURCE:源码中有效,编译时抛弃
      2. CLASS编译class文件时有效,一般会用到注解处理器
      3. RUNTIME:在运行期间,获取对应的注解,并做相关的处理
    • 常用元注解

      1. @Target():表示注解用在什么地方
        (例:value={ElementType.METHOD,ElementType.TYPE}
      2. @Retention():表示注解在什么地方还有效(例:value=RetentionPolicy.RUNTIME)
      3. @Documented:是否将注解生成在JAVAdoc中
      4. @Inherited:子类可以继承父类的注解
    • 注解的获取和使用:通过反射获取到Method对象后,有以下几个接口来获取注解内容

      • Method.getGenericReturnType():获取返回类型
      • Method.getAnnotations():获取方法的注解
      • Method.getParameterAnnotations():获取参数注解
    • Retrofit的注解类型
      (Retrofit在运行期间,配合Java动态代理,获取方法的参数和注解,并构造Requeset对象)

      • 网络请求和方法:@GET,@POST,@PUT,@DELETE 等
      • 标记类:@formUriEncoded,@Multipart,@Streaming
      • 网络请求参数:@Header,@headers,@URL,@Body 等



数据存储

  • 存储方式对比

    • SharedPreferences:键值对存储
    • 文件存储:存储二进制格式文件
    • ContentProvider:跨进程共享数据
    • SQLite:复杂对象存储,对数据增删改查

  • Room

    Room在SQLite上提供了一个抽象层,以便在充分利用SQLite功能的同时流畅的访问数据库

    • 主要的三个组件:

      • Database(数据库类):用于保存数据库并作为应用持久性数据底层连接的主要访问点
      • Entity(数据实体):用于表示应用的数据库中的表
      • DAO(数据访问对象):提供应该用于对数据库增删改查的方法
    • 使用

      1. Room接入
      dependencies {
          def room_version = "2.4.2"
          implementation "androidx.room:room-runtime:$room_version"
          kapt "androidx.room:room-complier:$room_version"
      }
      
      1. 设计数据表

      2. 新建Entity数据实例:
        用于定义表名和列名: 自定义一个User数据实体,User的每个实例都代表App数据库中的user表的一行

        • @PrimaryKey:表示单个主键,当主键为null且autoGenerate为true时可以帮助自动生成键值
        • @Columnlnfo:列名的注解
        @Entity
        data class User(
           @PrimaryKey(autoGenerate = true) val uid:Int?,
           @ColumnInfo(name = "first_name") var firstName:String?,
           @ColumnInfo(name = "last_name") var lastName:String?
        )
        
      3. 新增DAO接口
        定义需要用到的数据库操作方法:定义一个名为UserDao的DAO,用来对User表的增删改查

        @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>?
        
            @Query("SELECT * FROM user WHERE first_name LIKE :first AND last_name LIKE :last")
            fun findByName(first: String, last: String): User?
        
            @Insert
            fun insertAll(vararg users: User)
        
            @Delete
            fun delete(user: User)
        
      4. 新建数据库类,进行数据库配置,并需满足以下几个条件:

        a. 新增一个RoomDatabase的abstract子类(定义数据库版本等)

        b. 子类加注解@Database(entities=[], version=n),entities包含数据实体,将会在这个数据库中创建对应的表,version是数据的版本号

        c. 对于与数据库关联的每个DAO类,数据库类必须定义一个无参的抽象方法,并返回DAO类实例

        @Database(entities = [User::class], version=1)
        abstract class AppDatabase : RoomDatabase(){
           abstract fun userDao(): UserDao
        } 
        
      5. 获取db和dao对象 : 调用dao接口进行增删改查

    • Room原理

      1. 编译器,通过kapt处理@Dao、@Database注解,动态生成对应的实现类

        • Room在编译期,通过kapt处理@Dao和@Database注解,生成DAO和Database的实现类

        • AppDataBase --> AppDatabase_Impl

          1. 方法 createOpenHelper():生成包
          2. 方法 userDao():判断是否为空(单例模式)
        • UserDao --> UserDao_Impl

          1. 成员变量 __db:RoomDatabase的实例
          2. 成员变量 __insertionAdapterOfUser:EntityInsertionAdapterd实例,用于数据insert
          3. 成员变量 __deletionAdapterOfUser:EntityDeletionOrUpdateAdapter实例,用于数据修改或删除
      2. 底层使用Android提供的SupprotSQLite、OpenHelper实现数据库的增删改查等操作