Dependency Injection with Kotlin for Android newbies! (Koin,Retrofit and Coroutines)
Expectation is to get you up and running with dependency injection with Koin alongside with retrofit and Kotlin Coroutines in a minimal setup. no serious app architecture here !
Koin is not a DI Framework, a serious discussion here
Repo Links😎
- 💉 Koin — https://github.com/InsertKoinIO/koin
- 🌎 Retrofit — https://square.github.io/retrofit/
- 🔌 retrofit2-kotlin-coroutines-adapter — https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter
Why Koin? ( in comparison with dagger 2 )
- It’s a lightweight framework
- Less learning curve !
- less lines of generated code lines
- Easier to setup for newbies 😁
Also I saw few downpoints
- not a proper DI framework but a service locator (read more)
- No compile time dependency tree validations , you’ll know everything on runtime ? maybe not great for large projects.
TL;DR
kotlin-gradle-plugin_version = '1.3.21'
gradle_version = '3.4.1'
- Create a kt project in android studio and setup below dependencies
//Koin
implementation 'org.koin:koin-android:2.0.0-GA'
//Moshi
implementation "com.squareup.moshi:moshi-kotlin:1.8.0"
//Retrofit2
implementation "com.squareup.retrofit2:retrofit:2.5.0"
implementation "com.squareup.retrofit2:converter-moshi:2.5.0"
implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2"
2. Retrofit basics
Implementing retofit is pretty straightforward, first we implement the interface which contains the endpoints that we are going to call to
interface GitHubService {
@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String):
Deferred<Response<List<Repo>>>
}
See Deferred<Response<List<Repo>>> , Deferred value is a non-blocking cancellable future — it is a Job that has a result
“Repo” is the response model object for github search query (get it here)
Next we create the retrofit instance !
Koin needs a list of modules that need to be injected as a parameter ,for this I will create a class named “GitHubServiceAPI”, this class has a getGithubService function which returns a instance of GitHubService
class GitHubServiceAPI {
fun getGitHubService() : GitHubService {
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(MoshiConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.build()
return retrofit.create(GitHubService::class.java)
}
}
next we’ll setup koin to inject our GitHub service API to GlobelContext (read more )
this can be done in your Main Activity too , but I’ve created a class Extending Application to encapsulate koin setup from startup activity ( read on Why to extend an Application class?. )
Don’t forget to add this line inside the application tag of your AndroidManifest.xml
android:name=".MyApplication"
also internet permissions
<uses-permission android:name="android.permission.INTERNET" />
MyApplication.kt
class MyApplication : Application() {
var listofModules = module {
single { GitHubServiceAPI() }
}
override fun onCreate() {
super.onCreate()
startKoin {
androidLogger()
androidContext(this@MyApplication)
modules(listofModules)
}
}
}
inside list of modules , I’ve added GitHubSeriviceAPI as single which will genarete a singleton object, if we use as factory { GitHubServiceAPI() }
it will generate new instance each time you ask for this definition.
finally , get to your startup activity and call the githubservice !
learn more on coroutines https://android.jlelse.eu/coroutines-basic-terminologies-and-usage-b4242bd1b2a4
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) //Injected GithubServiceAPI
val serviceAPI: GitHubServiceAPI = get()
val gitHubService: GitHubService = serviceAPI.getGitHubService()
val call = gitHubService.listRepos("gsandaru")
CoroutineScope(Dispatchers.IO).launch {
val request = gitHubService.listRepos("gsandaru")
withContext(Dispatchers.IO) {
try {
val response = request.await()
if (response.isSuccessful) {
var data : List<Repo>? = response.body();
Log.d("MainActicity",
"Success ${data?.size} Repos Found")
} else {
Log.d("MainActicity",
"Error : Status ${response.code()} ")
}
} catch (e: Exception) {
Log.d("MainActicity",
"Exception ${e.message}")
}
}
}
}
}
get sourcecode here( https://github.com/gsandaru/Kotlin-Samples) , let me know any mistakes and glitches of this article in comments !
Happy Coding!
— — — — — —
LinkedIn — https://www.linkedin.com/in/gihansandaru/