Android Learning 9

知识填充 布局相关 LayoutInflater 在绑定Fragment的时候我们会用到LayoutInflater.inflate(), 该方法返回一个View对象,所以我们可以知道该方法的作用就是将xml布局文件加载为View或者ViewGroup对象。而LayoutInflater就是一个总的工具,有多个inflate方法。 获取LayoutInflater 1 2 3 LayoutInflater inflater1 = LayoutInflater.from(this); LayoutInflater inflater2 = getLayoutInflater(); LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); 后面两种其实走的都是第一种方法。this就是context。 .infalte()方法使用 .infalte()有多个重载的方法。 1 2 3 4 inflate(int resource, ViewGroup root) inflate(int resource, ViewGroup root, boolean attachToRoot) inflate(XmlPullParser parser, ViewGroup root) inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) 看源码可知,四个方法,前三个其实都是调用的第四个。 ...

<span title='2022-04-06 10:25:28 +0800 +0800'>April 6, 2022</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;YuanPeng11

Android Learning 8

今日份学习,综合之前学习过的知识,学习google推出的总结性APP - Sunflower https://github.com/android/sunflower 查漏补缺的同时将此APP进行本地化适配,因为使用的是wikimedia的源获取数据。 SunFlower 首先拉代码,跑起来,忘记有代码,然后看一下整个APP的结构。 首页的上半部分,一个title + header是固定,这块可以写在Activity中,header中有两个button,点击切换Fragment。 我的花园-Fragment: 用了一个GridView来展示添加的花园,这块的数据应该是是存入数据库的。 我的花园-植物详情-Fragment:点击我的植物后会进入到植物详情的Fragment,展示植物的详细信息,有一个返回按钮和分享按钮。 植物目录-Fragment: 同样是一个GridView来展示植物列表,这块的数据应该是从网络上拉取,缓存到数据库的。 植物目录-植物详情-Fragment:植物详情的Fragment就是展示从wiki上拉下来的植物数据,和我的花园的植物详情可以用一个Fragment。 植物目录-植物详情-添加植物-button:植物图片的下方有一个加号,可以进行植物的添加,植物添加后入库,然后我的花园页面显示。 还有一个给自己添加的植物浇水的功能,由于等待浇水的时间都比较长,所以先开发这些,后面再来浇水。梳理完毕,剩下的就是开整,使用现成的项目学习的话比较省事的是不用寻找静态资源。 IGarden 新建项目,起名就要IGarden吧,毕竟整个项目是个花园。为了方便,首先吧Sunflower需要的所有依赖以及静态资源全部导入。 CoordinatorLayout 这个Layout是2015年I/O大会上发布的Android Design Support Library,主要就是更好的使用material design。CoordinatorLayout是库中的一个FrameLayout,继承自ViewGroup。 顾名思义,协调者布局。为啥叫协调者?有点懵逼。CoordinatorLayout是一个"super-powered FrameLayout"。看了不少博文,终于还是有一点理解了,协调者协调的是child之间的联动,比如说有一个TopBar, TopBar下面有一个RecyclerView,当RecyclerView被滑动的时候如果我想隐藏TopBar怎么办?这时候就可以用协调者布局了。 那CoordinatorLayout是如何做到协调的呢?在CoordinatorLayout内部,每一个child都必须有一个Behavior,CoordinatorLayout根据这个Behavior去进行协调。那么Behavior到底是啥呢? 其实Behavior里面有一系列的方法,如下面所示 1 onStartNestedScroll(), onNestedScrollAccepted(),onStopNestedScroll(),onNestedScroll(), onNestedPreScroll(),onNestedFling(),onNestedPreFling() 所以说怎么协调的就很明了了,实际上就是使用触摸操作来控制View的滑动(我自己的理解)。 NestedScrolling 在Behavior方法中,这些方法的都有一个Nested的的标志,这个Nested又是干什么的呢?不得不说,Android东西可真多。先看下面的博文,但是下面的博文又说先让了解时间分发机制。 https://www.jianshu.com/p/aff5e82f0174 Android事件分发机制 关于Android事件,最常见的应该就是点击事件吧,对于一个View可以设置它的点击事件监听器。但是除了这个,还有巨多事件,从手指接触屏幕到手指离开屏幕的这一过程产生的一系列事件都叫做事件列。 具体的有下面的几个: MotionEvent.ACTION_DOWN 按下View开始 MotionEvent.ACTION_UO 抬起View MotionEvent.ACTION_MOVE 滑动View MotionEvent.ACTION_CANCEL 结束时间,非人为原因 ViewPager2 有点难以理解Sunflower如何做到在两个fragment之间滑动的,所以看了代码,发现是使用了ViewPager2+TabLayout来实现的。整体的代码实现其实不难,下面直接上代码吧。 首先在布局文件中定义TabLayout和ViewPage2,在ViewPager中可以添加控件,到ViewPager2就不行了,只能和TabLayout平级。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/header_title" android:layout_width="match_parent" android:layout_height="60dp" android:gravity="center" android:text="@string/app_name" android:textAppearance="?attr/textAppearanceHeadline5" android:textColor="@color/sunflower_white" android:textSize="30sp" /> <com.google.android.material.tabs.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="60dp" style="@style/Widget.MaterialComponents.TabLayout.Colored" app:tabIconTint="@drawable/tab_icon_color_selector" app:tabTextColor="?attr/colorPrimaryDark" /> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> 为了方便,直接使用了线性布局。 ...

<span title='2022-04-01 10:27:47 +0800 +0800'>April 1, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;YuanPeng11

Android Learning 7

今天学习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的实现类,根据命名我感觉原本的架构想法应该是对于数据调接口一个实现类,数据库操作一个实现类。 ...

<span title='2022-03-31 17:45:16 +0800 +0800'>March 31, 2022</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;YuanPeng11

Android Learning 6

昨日主要学习了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 ...

<span title='2022-03-30 15:48:57 +0800 +0800'>March 30, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;YuanPeng11

Android Learning 5

今天学习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类中定义方法来操作数据库。下面是一个简单样例: ...

<span title='2022-03-29 17:47:49 +0800 +0800'>March 29, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;YuanPeng11