今天学习Repository和WorkManager
Repository Repository pattern也是一种设计模式,叫做存储库模式。看一下官方的原文:
A repository mediates between data sources (such as persistent models, web services, and caches) and the rest of the app.
大意就是一个Repository相当于在数据源(持久化实体类,网络服务,缓存)和app其余的服务之间的中间层。简而言之,就是提供一个数据操作代理层。调用者不需要知道数据是从哪来,如何处理,只需要使用数据即可。这样有几个好处:
代码更容易维护,切换数据源的时候业务代码不需要更改
数据处理逻辑和业务逻辑分离,可以对这两个代码分别进行测试
减少代码重复
降低代码出错的几率
为什么要有Repository 经过前几天的学习,我们已经学习了ROOM以及DAO层数据的访问,那么还需要Repository干什么呢?通过上面的优点我们可以知道,避免直接访问数据。同事也解决了多数据源的问题,一个App的数据源可以是多个,数据库,接口等等。Repository对这两种情况进行封装,可以以一种统一的方式进行数据的拉取。
所以Repository其实是一种代码规范,并不是组件。
Repository例子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Singleton class PlantRepository @Inject constructor(private val plantDao: PlantDao) { // use the dao fun getPlants() = plantDao.getPlants() fun getPlant(plantId: String) = plantDao.getPlant(plantId) fun getPlantsWithGrowZoneNumber(growZoneNumber: Int) = plantDao.getPlantsWithGrowZoneNumber(growZoneNumber) // use the network service fun requestApi(): Plant } 项目中的实际运用 在市局测温项目中,实际上对Repository的使用更为复杂,整体的结构为首先定义一层datasource的接口类,然后在定义datasource的实现类,这里仅仅定义了一个remotedatasource的实现类,根据命名我感觉原本的架构想法应该是对于数据调接口一个实现类,数据库操作一个实现类。
...
昨日主要学习了ROOM和协程,今天补充一些协程的知识,并且学习RecyclerView, Adapter和WorkManager。
RecyclerView 在app中,有很多地方都需要用到列表来展示多个item,android提供了RecyclerView来支持大型列表,并且RecyclerView支持滑动,在显示有限个数量的item后,剩下的item需要滑动来获取。今天在昨天的睡眠质量的app的基础上将首页的历史记录改成使用RecyclerView来展示。
Adapter 适配器模式 在Android的学习中,有很多的设计模式可以学习,这次来到了适配器模式。
定义:用包装类来包装不兼容的对象,将一个类的接口转换成客户希望的另外一个接口。 举一个所有博文中都会举的一个例子,比如说在国际旅行的时候,在不同的国家充电器的规格都不一样,如果想要充电的话就需要转换器,那么这个转换器就相当于一个中间层,这个中间层就是Adapter层,通过这层来进行一个接口的转换达到兼容的目的。
关于具体的思想在下面的慢慢使用中体会
RecyclerView的使用 Step 1: 将所需要使用RecyclerView的布局添加RecyclerView
1 2 3 4 5 6 7 8 9 <androidx.recyclerview.widget.RecyclerView android:id="@+id/sleep_list" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toTopOf="@+id/clear_button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/stop_button" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/> Step 2:创建单个的Item的View,这里是TextView
...
今天学习android的数据库和协程
ROOM ROOM类似于JPA,能够定义DAO层使用预置的方法进行数据的操作。ROOM主要包含下面三个组件:
Database数据库类: 用于保存数据库并作为应用持久性数据底层连接的主要访问点。其实我感觉Database的类就是提供了Dao层的实例。
Entity实体类:用于表示应用的数据库中的表。
Dao类:提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。类似于Spring中的Dao层,定义了操作数据库的方法。
Entity 实体类就是我们常见的实体类,使用的注解也和JPA类似
@Entity(tableName = “users”):该注解说明该类是一个实体类,并且关联了users的表
@PrimaryKey:用于字段上,说明该字段是主键
@ColumnInfo(name = “last_name”):用于字段上,绑定实体类中的属性和表中的字段
1 2 3 4 5 6 @Entity(tableName = "users") data class User ( @PrimaryKey val id: Int, @ColumnInfo(name = "first_name") val firstName: String?, @ColumnInfo(name = "last_name") val lastName: String? ) Dao 在Dao类中定义方法来操作数据库。下面是一个简单样例:
...
技术学习 今日的技术学习内容为ViewModel和LiveData,这部分的内容相当于就是Android的架构学习,了解一个Android项目由哪些部分组成,如何去按照规范分层编写代码。
Android架构 MVVM(Model-View-ViewModel) Google 2015年I/O大会上推出了DataBinding的框架,使用了MVVM的模式,MVVM的思想就是从APP的业务逻辑中分离数据持久层。
Model: 实体类模型。Model提供了数据提取接口供ViewModel使用,经过数据转换和操作最终映射绑定到View层的某个UI元素的属性上。
View: 对应Activity和XML布局文件。不进行业务代码的编码,主要作用初始化控件,处理事件。简单地说:View层不做任何业务逻辑、不涉及操作数据、不处理数据,UI和数据严格的分开。
ViewModel: 负责完成View和Model之间的交互。ViewModel只做和业务逻辑和业务数据相关的事,不做任何和UI相关的事情,ViewModel 层不会持有任何控件的引用,更不会在ViewModel中通过UI控件的引用去做更新UI的事情。
https://tech.meituan.com/2016/11/11/android-mvvm.html
AAC(Android Architecture Components) Google 2017年I/O大会上发布了AAC,个人感觉就是在上述MVVM的基础上封装好了所有实现的组件,开发者仅需调用即可。其包含一下框架或者组件:
ROOM: 类似于JPA的持久层框架,用于数据的持久化解决方案。 WorkManager: 管理后台任务,类似于一个框架去管理后台的Service。 Lifecycle: 存储生命周期状态并且允许其它组件访问。 ViewModel: 上面MVVM架构中的ViewModel的实现,专注于业务的处理。 LiveData: 使用LiveData构建数据对象,在数据改变的时候,UI改变。 Navigation:导航,负责页面的跳转。 重点在于Room、ViewModel、LiveData、Navigation的使用,前面已经学习了Navigation,主要用于Fragment的跳转,可以定义不同的action,执行去执行该Action来进行不同Fragment的跳转。下面学习比较重要的ViewModel和LiveData。
LiveData 观察者模式 之前一直没有领悟到观察者模式的精髓,在Android中有很多地方都使用了观察者模式,比如,监听点击事件。对于观察者来说,它并不关心观察对象的数据是如何过来的,而只关心数据过来后进行怎样的处理。
LiveData格式 在写代码的时候根据固定的格式可以很轻松的写出LiveData的数据观察,ViewModel中定义LiveData,Fragment或者Activity中绑定ViewModel,然后监听LiveData的改变。
1 2 3 4 5 6 7 8 9 10 11 12 // viewModel中定义LiveData 以及LiveData改变的处理逻辑 // 下面这段代码就是定义了一个游戏结束的flag, private val _eventGameFinish = MutableLiveData<Boolean>() val eventGameFinish: LiveData<Boolean> get() = _eventGameFinish // 然后在fragment中监听LiveData的更新 根据LiveData中存储的flag进行不同的页面处理 viewModel.eventGameFinish.observe(viewLifecycleOwner, Observer { hasFinished -> if (hasFinished) { gameFinished() } }) 在其中有几个点需要明确一下:
...
Android学习的第三篇文章,跟着google的官方教程来到了lesson2,开始进行Layout的学习。
ViewGroups view的集合,构成了布局的结构。layout的构建使用有层级的View和ViewGroup对象。layout的结构如下:
LinearLayout 线性布局,UI元素被水平或者垂直摆放。
android:orientation: 布局方向,设置为水平或者垂直布局
horizontal: 水平,默认方向 vertical:垂直 android:layout_gravity: 子控件在父控件上的对齐方式
android:gravity: 控件内部的元素的对齐方式,支持多个方向,示例如下,下面的TextView中的text就在整个TextView的居中靠下的方向:
1 2 3 4 5 6 7 <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="bottom|center" android:text="TEST GRAVITY" android:textSize="50sp"/> android:layout_weight: 子控件在父控件中的权重,说白了就是占多大,比如说一个LinearLayout有5个button,每个button的weight都是1,那么其orientation方向上均分5分,每个button占1/5
其它的参数例如margin,padding等等和其它控件都是相同的,不赘述
RelativeLayout 相对布局,以相对位置显示子控件。说白了,就是可以指定子控件相对于其它控件的位置,比如说有两个buttonA和buttonB,如果想要buttonB布局在buttonA的右下方45度的未知,那么直接可以用两行就可以解决了,不需要嵌套多个LinearLayout。
1 2 android:layout_below="@+id/buttonA" android:layout_centerHorizontal="true" alignParentXx: 这个系列的参数都是相较于父控件而言的,相对于父控件停靠在哪个位置,Top, Bottom, left, right
...