对sunflower的整体分析
前言
sunflower是运用了Jetpack组件,而开发出的一个app,语言采用的是kotlin。本文要求大家应该对Jetpack组件,及kotlin语法有一定的了解。Android Jetpack组件推荐的使用项目架构:
注意所有的引用都是单向的,尤其注意viewModel会持有repository的引用。 而对数据的操作(通过Dao的增删查改)和网络请求都是在repository中完成的
sunflower项目的地址为:https://github.com/android/sunflower
项目的整体流程
该项目界面主要分为三个部分:
- gardenPlanting部分 -> 我的花园界面
- plantList部分 -> 植物列表的界面
- plantDetail部分 -> 植物的详情界面
注意:没有考虑gallery
部分,因为gallery
部分还需要申请API的密钥。
从数据库层面进行分析
分为garden_plantings
和plants
两个数据表
有两个data
实体类,GardenPlanting
和Plant
Plant
数据类对应plants
表,GardenPlanting
数据类对应garden_plants
表
plants
表:存储了所有植物的信息
这里数据的获取并不是来源于网络,而是来自于事先已经创建好了的assets目录下的json数组,并在数据库创建时,通过WorkManger
发送这个请求,把所有Plant
的信息insert
到plants表中。
garden_plantings
表:记录了plant的名字,种下日期,最后浇水的时间。
当你选择你要添加的植物(在植物的detail界面),就会根据plantId属性insert
到garden_plantings
表中。
此外,还有一个数据类PlantAndGardenPlantings
表示两个表之间的映射关系,一个Plant
,对应多个GardenPlanting
,两个表通过Plant的id与GardenPlanting的plant_id来联系,通过observe
方法,我的花园界面就会同步刷新。
为什么存在这个表,因为在我的花园界面,不仅要显示plants表中的信息,还要显示garden_plants表的信息。
小结:
我的花园界面即GardenFragment
对应的仓库是GardenPlantingRepository
,仓库中的Dao是gardenPlantingDao
,填充界面数据的实体类是PlantAndGardenPlantings
而不是GardenPlanting
植物列表即PlantListFragment
对应的仓库是PlantRepository
,Dao层是PlantDao
,填充界面数据所用到的类是Plant
类
植物的详情界面即PlantDetailFragment
对应的仓库有PlantRepository
和GardenPlantingRepository
,前者用于填充界面数据,后者则用于记录植物的添加及删除操作
从执行流程进行分析
- 找到程序的入口
<activity
android:name=".GardenActivity"
android:theme="@style/Theme.Sunflower.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- 进入到我的花园界面
如果运行了sunflower这个项目,app一打开就会进入到这个界面,那么它是怎么实现的呢?
此处会用到Navigation组件,GardenActivity
对应的xml中有一个控件,它有一个属性app:navGraph
,app:navGraph
: 属性赋值的是 nagation文件(类似是一个的导航图),用来管理fragment及跳转
<fragment
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_garden"/>
nav_garden
的可视化界面如下
注意箭头(action)代表的就是跳转方向,可能还会携带参数传递
,这个可以用插件实现。
比如说:跳转到plant的详情界面,肯定会需要plantId属性(来源于plants表),因为必须要知道是哪个plant的detail界面打开了。
所以此时就来到了与view_pager_fragment
所对应的HomeViewPagerFragment
,它大体采用的就是tablayout + viewpager2
,有两个页面,GardenFragment
和PlantListFragment
,默认选中的就是GardenFragment
页面,即我的花园界面
- fragment之间的跳转
第一次启动这个app,GardenFragment
界面没有plant
,点击add plant按钮,就会跳转到PlantListFragment
private fun navigateToPlantListPage() {
requireActivity().findViewById<ViewPager2>(R.id.view_pager).currentItem =
PLANT_LIST_PAGE_INDEX
}
在PlantListFragment
界面点击某植物会进入PlantDetailFragment
,如果某植物已经添加到我的花园中,就不会显示添加植物的button
相同地,在GardenFragment
也能跳转到PlantDetailFragment