Android dependency injection koin example
The following is a walk through for setting up dependency injection using the library Koin for an Android project. The finished project will be a one screen app, where you can type in a github account name and it will fetch the account detail and display it.
The gradle file
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' android { compileSdkVersion 28 defaultConfig { applicationId "com.example.android_di_koin_example" minSdkVersion 15 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } ext.versions = [ "androidx_lifecycle": "2.2.0-rc03", 'koin': '2.0.1' , 'retrofit': '2.6.1' , 'okhttp': '4.0.1' ] dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' // Lifecycle implementation "androidx.lifecycle:lifecycle-livedata:$versions.androidx_lifecycle" implementation "androidx.lifecycle:lifecycle-viewmodel:$versions.androidx_lifecycle" implementation "androidx.lifecycle:lifecycle-extensions:$versions.androidx_lifecycle" kapt "androidx.lifecycle:lifecycle-compiler:$versions.androidx_lifecycle" //Okhttp implementation "com.squareup.okhttp3:okhttp:$versions.okhttp" implementation "com.squareup.okhttp3:logging-interceptor:$versions.okhttp" //Retrofit implementation "com.squareup.retrofit2:retrofit:$versions.retrofit" implementation "com.squareup.retrofit2:converter-gson:$versions.retrofit" implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2' // coroutines implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc03" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0' // Retrofit 2 for network tasks implementation 'com.squareup.okhttp3:logging-interceptor:4.0.1' implementation 'com.google.code.gson:gson:2.8.6' //Koin implementation "org.koin:koin-android:$versions.koin" implementation "org.koin:koin-androidx-scope:$versions.koin" implementation "org.koin:koin-androidx-viewmodel:$versions.koin" }
GithubAccount.kt, the data class for modeling the github account data.
import com.google.gson.annotations.SerializedName data class GithubAccount( @SerializedName("login") var login : String = "", @SerializedName("id") var id : Int = 0, @SerializedName("avatar_url") var avatarUrl : String = "", @SerializedName("created_at") var createdAt : String = "", @SerializedName("updated_at") var updatedAt : String = "")
GithubApi.kt, the Retrofit interface for the github api.
import kotlinx.coroutines.Deferred import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path interface GithubApi { @GET("/users/{username}") fun fetchGithubAccountAsync(@Path("username") username: String): Deferred> }
GithubRepository.kt, the repository for managing the api calls.
import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.withContext class GithubRepository(private val githubApi: GithubApi) { suspend fun getGithubAccountAsync(accountName: String): Deferred{ return withContext(Dispatchers.IO) { async { try { // for demo purpose, hence no error checking githubApi.fetchGithubAccountAsync(accountName).await().body() as GithubAccount } catch (e: Exception) { e.printStackTrace() null } } } } }
The above are just for setting up the project, here starts the Koin configuration. First, the NetworkModule.kt, provides the components needed for REST services. single means provide a singleton.
val networkModule = module { // Provide Gson single{ GsonBuilder().create() } // Provide HttpLoggingInterceptor single { HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY } } // Provide OkHttpClient single { val cacheDir = File((get () as MyApp).cacheDir, "http") val cache = Cache( cacheDir, 10 * 1024 * 1024 // 10 MB ) OkHttpClient.Builder() .cache(cache) .addInterceptor(get ()) .build() } // Provide Retrofit single { Retrofit.Builder() .client(get ()) .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create(get ())) .addCallAdapterFactory(CoroutineCallAdapterFactory()) .build() } // Provide GithubApi single { get ().create(GithubApi::class.java) } }
RepositoryModule.kt
val repositoryModule = module { // Provide GithubRepository single { GithubRepository(get()) } }
ViewModelModule.kt
val vmModule = module { // Provide MainActivityViewModel viewModel { MainActivityViewModel(get()) } }
Initializing Koin with the desired modules in the application class.
class MyApp : Application() { private val appModules = listOf( repositoryModule, networkModule, vmModule ) override fun onCreate() { super.onCreate() startKoin { androidLogger() androidContext(this@MyApp) modules(appModules) } } }
MainActivity.kt
class MainActivity : AppCompatActivity() { private val mainActivityViewModel: MainActivityViewModel by viewModel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mainActivityViewModel.githubAccount.observe(this, Observer { tv_content.text = it.toString() }) btn_fetch.setOnClickListener { mainActivityViewModel.fetchAccount(et_account.text.toString()) } } }
MainActivityViewModel.kt
class MainActivityViewModel constructor(private val githubRepository: GithubRepository): ViewModel() { private val _githubAccount = MutableLiveData() val githubAccount: LiveData get() = _githubAccount fun fetchAccount(accountName: String) { viewModelScope.launch { val githubAccount = githubRepository.getGithubAccountAsync(accountName).await() githubAccount?.let { _githubAccount.value = it } } } }
Search within Codexpedia
Search the entire web