iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 17
0
Mobile Development

30天,從0開始用Kotlin寫APP系列 第 17

Day 17 | 用 Kotlin 實作 MVVM 中的 Repository Layer

  • 分享至 

  • xImage
  •  

資料已經讀進來,那麼接下來要 Follow MVVM 的架構和資料溝通方法

接下來教學主體都會圍繞著這張圖

Repository Pattern

當資料的來源有多個時,使用 Repository Pattern 來處理算是滿常見的操作,透過 Repository 層接收多個來源的資料,然後開放特定的接口釋出資料,當外部物件操作資料時只能透過這些接口來存取,例如上面那張圖的資料來源就有兩個

  • Webservice
  • Local Database (SQLite)

那麼 ViewModel 需要操作資料就必須透過 Repository 的接口

開始撰寫 Repository Layer

那該要怎麼開始呢?
依照我目前的經驗是只要和異步工作有關的,那應該都會在 Repostirory 層處理,因為不論是從 DB 或是 Server 取資料,都是需要花時間去等待資料回來的,因此在這樣的前提下我們可以開始撰寫 RetrofitRepository

PirateList Repository

那首先先來處理 PirateList 的部份,那根據昨天和前天完成的 Code ,今天就是要把他們搬到 Repository 層,然後在把異步的部份處理的更完善

1. 建立 PirateListRepository.kt

data/repository 中建立 PirateListRepositroy.kt 的檔案

2. 實作 PirateService

前天在 MainActivity 有簡單的驗證 Retrofit 是可行的,那時是先實作 PirateService,因此這邊的概念也是一樣,要先把 PirateService 實作起來,因此在 Class 中先加入下面的 Code

private val pirateService: PirateService =
        NetworkManager.provideRetrofit(NetworkManager.provideOkHttpClient()).create(PirateService::class.java)

3. 建立 Suspend Function 非同步取得資料

Kotlin 本身有支援協程Coroutine ),那我們可以在函式前面加上 Suspend 裝飾詞,告訴 Compiler 這個函式是允許函式被暫停( Suspended ),並在之後再回復( Resumed )執行,那會有這樣的作法就是不希望一個 Job 鎖住太久的 CPU 資源,適當的釋放資源讓其他 Job 也有機會被同時完成,更詳細的介紹會在下面補上

因此這邊就要先創建一個 suspend fun 並取名為 fetchPirateList,其中可以注意到

  • fetchPirateList 帶了兩個 function 當作參數,目的是要做 Callback
  • 使用到了 flowflow 是 kotlinx-coroutines 支援的異步方法,很多人會拿他和 RxJava 做比較,因為他們要處理的問題是相同的
  • 最後一行是 Dispatchers.IO ,告訴 flow 裏面的工作需要跑在 worker thread 上,通常會用來執行比較耗時的 Job
suspend fun fetchPirateList(
        onSuccess: () -> Unit,
        onError: (String) -> Unit
    ) = flow {
        val response = pirateService.fetchPirateList()
        response.suspendOnSuccess {
            if (data != null) {
                val pirates: List<Pirate> = data?.results ?: listOf()
                emit(pirates)
                onSuccess()
            }
        }.onError {
            onError(message())
        }.onException {
            onError(message())
        }
    }.flowOn(Dispatchers.IO)

因此完整看起來會是這樣

4. 導入 Flow

那上面沒有提到的是 Flow Library 需要加到 dependencies 才能使用

dependencies {
...

// kotlinx.coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'

...
}

5. 建立 PirateDetailRepository.kt

那同樣的作法我們可套用到 fetchPirateInfo
那這邊可以注意到一件事,是我採用了 safe castElvis OperatordataPirateInfo 之間的轉型,這樣可以確保不會有 null 的發生,頂多建出一個 id = 0PirateInfo 物件

結語

今天介紹了 Repository 大概會處理哪些東西,以及大致上架構會長怎樣,那目前應該只需要這兩個 Repository ,如果之後還需要其他 Repository 會在另外建立
今天寫完也讓我找到明天要介紹的題目就是 Coroutine ,這也是我近期一直鬼打牆的部份,剛好可以透過這的整理看能不能突破以前自己一直沒搞清處的部份

Reference


上一篇
Day 16 | 在 Sandwish 中夾入 Retrofit - Part 2(半完結)
下一篇
Day 18 | Kotlin 中處理異步的好伙伴 - Coroutine
系列文
30天,從0開始用Kotlin寫APP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言