还记得便利贴专案做到哪了吗?专案目前用的架构模式是 MVVM :Jetpack Compose 所做成的 View, BoardViewModel
还有 InMemoryNoteRepository
,其中间的资料更新机制是由 RxJava 来完成。但是,我们有写任何的 subscribeOn
或者是 observeOn
吗?完全没有,对吧!所以目前来说,任何的程序码,不管是 View, ViewModel 还是 Model 都是在 Main thread 上执行的。
由於之前所示范的都是在本地端执行的,所以没有什麽太大的必要硬要去切换执行绪,如果写了subscribeOn
或者是 observeOn
还有点多此一举的感觉,对吧?但是今天就需要用到他们了,今天会使用 Firebase Firestore 来当作专案的资料储存中心,在传输资料的过程中会需要连上网路,因此我们就需要在某些地方进行执行绪切换,才能确保程序运行无误。
原本的 InMemoryNoteRepository
将会被 Firestore 的实作给取代,根据 SOLID principle 的 Liskov substitution principle ,在抽换实作时,不应该影响原有的行为,所以 BoardViewModel
与 View 层的所有程序码都不会因为抽换实作而需要修改内容,这是非常重要的一件事,如果今天只是因为换了 Repository 的实作而让 BoardViewModel
的运作机制变了,那就表示设计上是有问题的,职责不够专一,可能就要考虑先重构,等到行为确定不会有问题时再换实作。
FireStore 是一个有弹性、易扩展的 NoSQL 云端资料库,可以用来储存还有同步客户端以及服务器端的资料,该资料库的特性为:灵活的数据结构、简易查询、实时更新、离线支持、为扩展而设计,以下列出几个对於便利贴 APP 来说很方便的特性:
至於其余特性想了解更多的,请查看 Firestore 官方文件:https://firebase.google.com/docs/firestore
Firebase 在官方文件中的繁体翻译是:“火力地堡”,听起来像是一个很厉害的防御基地XD
在 Firebase console 中增加一个新专案,并在专案名称中输入“StickyNote”
在步骤二的时候选择不启用 Google Analytic,建立专案就完成了!
进入专案後,你将会在左边的侧边栏上看到“Firestore Database”,点选它
接着再点击画面中间的“建立资料库”
在左边侧边栏点选“专案总览”,然後在萤幕中间你将会看到一个 Android 小绿人的图案:
点击 Android 小绿人之後,输入应用程序套件名称,以我的例子是“com.yanbin.stickynote”,其他栏位暂时都不需要填,接着下载“google-service.json”,下载完之後将档案放到根目录底下。
使用 gradle 来新增 Firebase SDK:
apply plugin: 'com.android.application'
// Add this line
apply plugin: 'com.google.gms.google-services'
dependencies {
// Import the Firebase BoM & firestore
implementation platform('com.google.firebase:firebase-bom:28.4.0')
implementation "com.google.firebase:firebase-firestore"
}
最後点击 Android studio 上的 Sync,大功告成!
如果不想因为实验而弄坏资料库的话,也可以考虑这个 Codelab 中教学的使用 Firebase Emulator:https://firebase.google.com/codelabs/firestore-android#0
接下来就试试看在 Firebase console 上新增资料吧,之後本地端就可以使用 SDK 来获取这上面的资料,让我们回顾一下资料格式是长怎样的:
data class Note(
val id: String,
val text: String,
val position: Position,
val color: YBColor) {
companion object {
fun createRandomNote(): Note {
val randomColorIndex = Random.nextInt(YBColor.defaultColors.size)
val randomPosition = Position(Random.nextInt(-50, 50).toFloat(), Random.nextInt(-50, 50).toFloat())
val randomId = UUID.randomUUID().toString()
return Note(randomId, "Hello", randomPosition, YBColor.defaultColors[randomColorIndex])
}
}
}
data class Position(val x: Float, val y: Float) {
operator fun plus(other: Position): Position {
return Position(x + other.x, y + other.y)
}
}
data class YBColor(
val color: Long
) {
companion object {
val HotPink = YBColor(0xFFFF7EB9)
val Aquamarine = YBColor(0xFF7AFCFF)
val PaleCanary = YBColor(0xFFFEFF9C)
val Gorse = YBColor(0xFFFFF740)
val defaultColors = listOf(HotPink, Aquamarine, PaleCanary, Gorse)
}
}
每一个 Note 会有这些资料储存在资料库中:id, text, position, color。心里有个底之後,我们就先来试试看 Firestore 是如何新增资料的:
点选新增集合,他要你输入集合 ID,先在此输入“Notes”,点选下一步。
下一个出现的是新增文件,点选自动产生的 ID,这里的每一个文件将会对应到我们的资料结构: Note 。接下来我们将每个需要的栏位一一填入:
text
,类型选择 string 不用改,至於值的部分就先填入 “Hello”为什麽位置不是使用 number 而是 string 呢?其实也没有什麽不行...真要说原因的话,就是我之前在实作时以为 number 只能使用整数,後来查文件才知道 number 也可以是小数点,就将错就错了...但是也不是什麽大问题,最後需要的时候再改过来就行了,这边是容易修改的技术细节。
最後我是选择扁平的 position ,因为这样比较单纯而且在接资料时也相对简单,新增完资料之後会像下面这样子:
SDK 跟後台设定都已完成,明天会来进行资料串接。
>>: D-15.Rspec 从零开始写测试(三) shoulda-matchers && Distribute Candies
实现思维: 一、用 tkinker file ask 方法配合按钮,执行按钮就开始选择路径照片, 并...
-VPN 访问(来源:ActForNet) VPN 是一种通过隧道连接节点的虚拟网路。L2F、PP...
如图 pancode: div 设计成 各种形状 三角形。五角形 六角形 的方法 制作参考引用 ht...
事情来自某天我在找资料的过程中,看到有些大大提供了事件纪录档的文本说明,所以今天要来试着阅读.evt...
90. Subsets II 今天挑选了「90. Subsets II」的题目,这是一道类似「排列...