这是我参与「第四届青训营 」笔记创作活动的的第4天
UI组件:View & ViewGroup
布局:LinearLayout 、 RelativeLayout 、 FrameLayout 、 ConstraintLayout
绘制:布局加载 、 布局解析 、 UI渲染
交互:获取View实例、常用交互事件 、 触摸事件 、 事件分发
动画:帧动画 、 补间动画 、 属性动画
自定义View:创建View 、 处理布局 、 绘制、交互 、 动画
App内容的获取,都是通过网络请求。

Retrofit是目前Android平台上,可以说是最热门的网络请求封装框架是对OkHttp的一个封装。
接口:xxxx/users/{uid}/name
类型:get请求
GitHub官方仓库查看最新版本

引入


定义说明:
接口类名:可自定义,尽量和这类请求的含义相关
函数名:可自定义,需要能识别出该接口的作用,该interface里可以增加多个不同的函数
@GET 注解:用于指定该接口的相对路径,并采用Get方法发起请求
@Path 注解:需要外部调用时,传入一个uid,该uid会替换@GET注解里相对路径的{uid}
返回值Call:·返回值Call:这里用ResponseBody,可以直接拿到请求的String内容如果要自动转为Model类,例如User,这里直接替换为User就好。


Cronet与OkHttp的区别:

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


由于Retrofit用到了非常多的注解,这里先做个知识普及注解,也可以理解为是一个标签,这个标签可以加在类、方法、参数、成员变量上,并且可在合适的时机读取注解的内容,进行处理。
@Overrride:标注一个方法是重写了父类的实现
@Nullable:标注所描述对象有可能为空
有定义和使用注解的地方,肯定还需要有获取注解并处理注解内容的地方,不然这个注解也就没什么用了。
3个时机 → 注解的生命周期@Retention
SOURCE:只有在源码中有效,编译时抛弃。例如:@Override
CLASS:编译class文件时有效,一般会使用到注解处理器。
RUNTIME:在运行期间,获取对应的注解,并做相关的处理。

@Target:指定作用的对象,这里是个METHOD,说明这个注解是作用在方法上,其他枚举值:
PARAMETER:参数
FIELD:类成员
…
@Retention:指定注解的生命周期,这里是RUNTIME,说明这个注解要保留到运行时。
通过反射获取到Method对象后,有以下一些接口来获取注解类型:
Method.getGenericReturnType()获取返回类型
Method.getAnnotations()获取方法的注解
Method.getParameterAnnotations()获取参数注解

Retrofit是在运行期间,配合Java动态代理,获取方法和参数的注解,并构造Request对象。
java动态代理:Proxy.newProxyInstance
利用Java的反射技术(Java Reflection),代理某个interface,一旦调用interiace里的某个方法时,实际通过代理调用InvocationHandler的invoke方法。
通过Method对象,就可调用Method.getAnnotations()Method.getParameterAnnotations()来获取该方法和方法参数的注解内容。




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


Retrofit构建行数中,如果未指定callFactory , 则会自动创建一个OKHttpClient

创建好的OKHttpClient将会保存在Retrofit实例中。
ExecutorCallAdapterFactory主要是用来控制Retrofit在子线程触发请求,在主线程回调结果。

通过代理对象调用接口方法IUserInfoService#getUserName()时,会触发InvocationHandler#invoke方法。

替换底层用到的OkHttpClient
替换底层用到的OkHttpCall


持久性的本地数据存储是Android中常见的能力,可以在应用被杀死的情况下,而保持数据不会被清除。可以根据不同场景的诉求,可以选用不同的存储方式,常见的数据存储主要有以下4种。


Room是Google Jetpack家族里的一员,Room在 SQLite 上提供了一个抽象层,以便在充分利用SQLite的强大功能的同时,能够流畅地访问数据库。

数据库类(Database),用于保存数据库并作为应用持久性数据底层连接的主要访问点。
数据实体(Enity),用于表示应用的数据库中的表。
数据访问对象(DAO),提供应用可用于查询、更新、插入和删除数据库中的数据的方法。
Gradle目录的build.gradle文件里添加:


3个字段

1.所有的属性必须是public、或者有get、set方法。
2. @PrimaryKey:表示单个主键,当主键值为null且autoGenerate为true时可以帮助自动生成键值。
3. @ColumnInfo:列名的注解

5.1 新增一个RoomDatabase的abstract子类
5.2 子类需加注解@Database(enity = [xxx],version = n),enities包含数据实体,将会在这这个数据库中创建对应的表,version是数据的版本号。
5.3 对于与数据库关联的每个DAO类,数据库类必须定义一个无参的抽象方法,并返回DAO类实例。


核心:
1.编译期,通过kapt处理@Dao、@Database注解,动态生成对应的实现类
Room在编译期,通过kapt处理@Dao和@Database注解,生成DAO和Database的实现类。
AppDatabase --> AppDatabase_Impl
UserDao–>UserDao_Impl
kapt生成的代码在build/generated/source/kapt

AppDatabase_Impl:数据库实例的具体实现,自动生成:
createOpenHelper(): Room.databaseBuilder().build()创建Database时,会调用实现类的createOpenHelper()创建SupportSQLiteOpenHelper,此Helper用来创建DB以及管理版本
userDao():创建UserDao_Impl
AppDatabase_Impl的2个具体实现:
createOpenHelper()
userDao()
UserDao_Impl:UserDao的具体实现,自动生成,主要有以下3个成员变量以及UserDao里定义的接口。
3个核心的成员变量:
_db : RoomDatabase的实例
_insertionAdapterOfUser : EntityInsertionAdapterd实例,用于数据insert
_deletionAdapterOfUser: EntityDeletionOrUpdateAdapter实例,用于数据的update/delete
n 个是UserDao里自己定义的接口的具体实现:
insertAll()
delete()
getAll()
loadAllByIds()
findByNames()

UserDao_Impl#insertAll():
使用_db开启事务,
使用_insertionAdapterOfUser执行插入操作

UserDao_Impl#delete():
使用_db开启事务,
使用_deletionAdapterOfUser执行删除操作

UserDao_Impl#getAll():
1.自动生成sql语句 "SELECT * FROM USER”
2.获取到数据库的 Cursor光标
3.使用Cursor循环读取数据库的每条记录
4.将Cursor里的内容,读取出来, 并保存在List中返回


相关资料:
Retrofit官网:https://github.com/square/retrofit
Android开发者文档——Room的使用:https://developer.android.com/training/data-storage/room?hl=zh-cn