iT邦幫忙

2021 iThome 鐵人賽

DAY 30
0
Mobile Development

如何開發適合電子書閱讀器使用的瀏覽器 Android APP系列 第 30

電子書閱讀器上的瀏覽器 [Day30] 導入 Koin

原本今天最後一篇,只想做個總結,放放相關連結而已。不過剛好昨天心血來潮幫 EinkBro APP 導入了 Koin 的支援,今天就順手也記錄一下,讓大家當做參考。

導入 Koin

什麼是 Koin

官網在此

這網路上的文件已經多到泛濫了,不過因為要導入它,還是稍微簡單幾句說明一下。

Koin 是一套用來解決 dependency injection 的函式庫。在 Android 這些年來的發展下,常用的解決方案也有好幾套,像是早期較多人使用的 Dagger2,跟後來 Google 自家推出的 Hilt。而 Koin 標榜的是以 Kotlin 開發,利用 Kotlin 語法特性,讓開發者可以很方便地達成 dependency injection 的目的。

為什麼選擇 Koin

既然有這麼多選擇,為什麼要採用 Koin,而不是其他方案呢?Dagger2 很久以前有使用過,因為整套架構比較大些,要產生比較多的 class 和 boilerplate codes,對於一個下班時間偶爾寫寫的案子來說,用到 Dagger2 有點殺雞用牛刀的感覺。而 Hilt 則是因為還沒研究過,所以就直接導入了 Koin 來改善目前程式裡的一些實作問題。

導入方法

官網第一頁就直接寫了幾段 code snippet,展示可以多麼容易的使用 Koin。但畢竟 sample code 就是 sample code,往往跟實際實作時要處理的複雜度不一樣。

新增引用函式庫

首先要先加一下它的相關 libraries 在 build.gradle 中

def koin_version = "3.1.2"
// Koin core features
implementation "io.insert-koin:koin-core:$koin_version"
// Koin test features
testImplementation "io.insert-koin:koin-test:$koin_version"
// Android
implementation "io.insert-koin:koin-android-compat:$koin_version"

初始化 Koin

在 APP 的 Application class 實作中,初始化 Koin 函式庫。

class EinkBroApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        ...
        startKoin {
            androidContext(this@EinkBroApplication)
            modules(myModule)
        }
    }
}

上面寫到的 myModule 參數,會在下面介紹到。

建立想要被注入的元件,並塞到 modules 中

因為目前我想要抽出來的元件還不多,所以我直接在 EinkBroApplication.kt 檔案中建立 myModule 參數:

val myModule = module {
     single { ConfigManager(androidContext()) }
     single { PreferenceManager.getDefaultSharedPreferences(androidContext()) }
     single { BookmarkManager(androidContext()) }

     single { DialogManager(it[0]) }
     single { EpubManager(it[0]) }
 } 

ConfigManager 是重構原本的程式後,把大部分常會用到的 SharedPreferences 讀寫操作都定義在裡頭。除了 BrowserActivity class 會用到它以外,在很多其他的 class 中也有讀寫 preference 的需求,所以用注入的方式會比在每個地方都生成一份來得好。

BookmarkManager 是書籤的 db 操作實作,也是除了 BrowserActivity 外,還有其他地方用得到。透過 Koin 讓大家都能使用同一個 instance 就足夠了。

最後兩個 DialogManager()EpubManager,因為需要 Activity 當 constructor 的參數,所以這邊會需要使用到的人傳入當下的 Activity,待會兒會介紹到為什麼這邊要使用 it[0] 當參數。

實作需要注入的 classes

這邊就稍微講一下 BrowserActivity 裡的修改就好。更多的內容可以直接看下面的 git commit 連結。

open class BrowserActivity: ... {
-  private val sp: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
-  private val config: ConfigManager by lazy { ConfigManager(this) }
+  private val sp: SharedPreferences by inject()
+  private val config: ConfigManager by inject()

-  private val bookmarkManager: BookmarkManager by lazy {  BookmarkManager(this) }
+  private val bookmarkManager: BookmarkManager by inject()

-  private val epubManager: EpubManager by lazy { EpubManager(this) }
+  private val epubManager: EpubManager by inject { parametersOf(this@BrowserActivity) }

}

原本用 by lazy 建立的一些元件,現在直接透過 Koin 包好的 by inject() 就可以取得在 EinkBroApplication 中建立好的各個元件。而 EpubManager 的部分可以看到,我們在 inject 時,多加了 parametersOf() 的 argument,讓我們可以傳入想要的特定參數到它的 constructor 中。這樣子剛剛上一小節寫的 it[0] 就會拿到我們這邊 parametersOf() 中的第一個參數。

之所以在 Activity 中能使用 by inject(),是因為 Koin 已經在常見的元件中加入了相關支援。如果是自己建立的 class 裡也想要利用 by inject()注入需要的元件的話,只要幫 class 加入 KoinComponent 的繼承關係就行了,也是一行 code 的事,下面的 NinjaWebView 就是這樣修改的:

class NinjaWebView : WebView, AlbumController, KoinComponent {
...
-  private val sp: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
-  private lateinit var config: ConfigManager
+  private val sp: SharedPreferences by inject()
+  private val config: ConfigManager by inject()

導入 Koin 後,適合只保留一個實例的元件,就不用再在每個 class 中建立了。

因為這個 APP 原先都沒有寫什麼測試的程式碼,我在開發時也都是以功能開發為主,自己玩個幾天,沒有什麼大問題就會發佈出去,所以 Koin 的導入並不會拿來利用在測試中。以後如果有適合的場景的話,說不定我會拿來試試。

以上就是導入 Koin 的簡單介紹。當然 Koin 還有很多進階的功能,不過目前對我來說,因為都還用不上,這裡也就不多做描述了。

參考原始碼連結

https://github.com/plateaukao/browser/commit/5b71dd2dba9557e87d2632b43eb0cb5c345366c0

總結

終於來到了這系列的最後一篇。

這三十天來,每天一點一點地介紹了這半年來對於電子書閱讀器上自己開發的瀏覽器APP的功能實作細節。礙於篇幅和每日可以準備的時間長度,有些太細節的內容都沒有來得及寫出來。

儘管鐵人賽將在這篇劃上句點,但對於這個 browser APP 開發還是持續在進行中的。除了會不斷改善其性能外,也會逐漸加入更多適合閱讀器的功能。如果有讀者想要了解更多相關開發內容的話,可以參考本文最後的相關參考連結,繼續關注這個 APP 的開發方向。

目前這個 browser app (EinkBro) 在 Google Play Store 上也已經有上架。由於 Google Play Store 不是每個閱讀器都有內建,所以 EinkBro 也提供了好幾個不同的安裝管道:除了 Play Store App 可以下載外,也可以直接在 Github.com 上取得每一版最新的 release apk。然後,還有 [Day28] 介紹到的 F-droid 能夠下載。

全系列相關連結


上一篇
電子書閱讀器上的瀏覽器 [Day29] 網頁載入性能改善
系列文
如何開發適合電子書閱讀器使用的瀏覽器 Android APP30

尚未有邦友留言

立即登入留言