Keyword:Koin,Koin Compent
到Day20 使用Koin管理依賴注入顯示在Android上 放在這邊
KMMDay20
我們先在Android使用昨天建立的Koin物件吧.就跟正常的Koin使用流程一樣,需要在Android的App啟動時進行Koin的啟動,因此我們在Android的根目錄建立一個新的物件CafeApplication並且繼承Application,讓Koin可以在這裡啟動,有多第三方庫也會要求使用時必須在Application預先載入.如果有用到其他部分的組件,請務必在Koin之後再開始啟動流程.不然這塊的物件就會超脫Koin的管理,這樣就失去了依賴注入的特性了.
import android.app.Application
import android.content.Context
import com.officeyuli.kmmforit.initKoin
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
class CafeApplication : Application() {
override fun onCreate() {
super.onCreate()
initKoin(
module {
single<Context> { this@CafeApplication }
viewModel { MainViewModel() }
}
)
}
}
在這裡我們呼叫了昨天寫好的一個funcion ,initKoin,回去看initKoin有要求提供一個appModule,這邊就交由各平台實作.那Android這邊有兩個特別的物件建立或提供,第一個就是ApplicationContext,不管是使用DB或是SharedPreferences都需要這個,所以先交給Koin幫我們管理(當然在iOS就沒有需要這個了),在幾天後的DB使用教學就會用到了
另外一個就是ViewModel,在一般的Android App裡面,使用ViewModel的時候需要提供生命週期的宿主,像是某一個Activity或是Fragment,但是我們藉由Koin提供的DSL,可以自動根據ViewModel所在的View層物件,來自動建立對應的ViewModel.是不是很方便呢.
這邊有一點要特別注意,因為viewModel這個Term太多人使用了,在使用Koin的viewModel功能時,要注意不要使用到錯誤的import.所以我今天特別把import加了上去.
接下來要讓Android系統知道啟動的時候要呼叫這個Application,所以修改androidApp內的AndroidManifest.xml.在application的tag內加上指定的Application,也就是剛剛建立的CafeApplication.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.officeyuli.kmmforit.android">
<application
android:name=".CafeApplication"//加入這行來指定啟動時使用的預設Application
android:allowBackup="false"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
...
>
</activity>
</application>
</manifest>
然後我們修改MainViewModel,讓其實作KoinComponent這個interface.這是為了讓Koin可以提供,我們不用做特別的動作.
然後根據我們昨天寫的Module,現在Koin知道如何提供DataRepositoy的實體了,那麼我們可以使用by inject()方法,讓Koin來代替我們完成物件的建立.現在MainViewModel不用知道這些物件怎麼建立的了.
class MainViewModel : ViewModel(), KoinComponent {
private val dataRepository: DataRepository by inject()
private val cafeList = MutableLiveData<List<CafeResponseItem>>()
val cafeListLiveData: LiveData<List<CafeResponseItem>> = Transformations.map(cafeList) { it }
fun fetchCafeData(city: String = "") {
viewModelScope.launch() {
val result = async { dataRepository.fetchCafesFromNetwork(city) }
cafeList.value = result.await()
}
}
}
同樣的,Activity內的viewModel宣告,由於Koin已經自動幫我們建立好了ViewModel的建立過程,因此可以由Koin代為效勞.我們把裡面的MainViewModel建立過程替換掉.
import org.koin.androidx.viewmodel.ext.android.viewModel
class MainActivity:AppCompatActivity() {
...
private val viewModel : MainViewModel by viewModel()
...
}
同樣要注意viewModel不要用錯了,要import的是koin的.
之前我們的ViewModel是可變數var,而在使用Koin提供後,會要求改變為不可變數val,這樣就不會在使用流程中,再次的重新定義給viewModel變數了.這樣物件的建立與銷毀都由Koin來管理.
執行起來,跟原本的狀態是一樣的,但是MainActivity ,MainViewModel與DataRepository的耦合程度大大的降低了.
今天完成了Android的部分,我們明天會來做iOS的部分