Dependency Injection with Kotlin Koin in Eventyay Attendee
Eventyay Attendee Android app contains a lot of shared components between classes that should be reused. Dependency Injection with Koin really comes in as a great problem solver. Dependency Injection is a common design pattern used in various projects, especially with Android Development. In short, dependency injection helps to create/provide instances to the dependent class, and share it among other classes. Why using Koin?Process of setting up Koin in the applicationResultsConclusionResources Let’s get into the details WHY USING KOIN? Before Koin, dependency injection in Android Development was mainly used with other support libraries like Dagger or Guice. Koin is a lightweight alternative that was developed for Kotlin developers. Here are some of the major things that Koin can do for your project: Modularizing your project by declaring modulesInjecting class instances into Android classesInjecting class instance by the constructorSupporting with Android Architecture Component and KotlinTesting easily SETTING UP KOIN IN THE ANDROID APPLICATION Adding the dependencies to build.gradle // Koin implementation "org.koin:koin-android:$koin_version" implementation "org.koin:koin-androidx-scope:$koin_version" implementation "org.koin:koin-androidx-viewmodel:$koin_version" Create a folder to manage all the dependent classes. Inside this Modules class, we define modules and create “dependency” class instances/singletons that can be reused or injected. For Eventyay Attendee, we define 5 modules: commonModule, apiModule, viewModelModule, networkModule, databaseModule. This saves a lot of time as we can make changes like adding/removing/editing the dependency in one place. Let’s take a look at what is inside some of the modules: DatabaseModule val databaseModule = module { single { Room.databaseBuilder(androidApplication(), OpenEventDatabase::class.java, "open_event_database") .fallbackToDestructiveMigration() .build() } factory { val database: OpenEventDatabase = get() database.eventDao() } factory { val database: OpenEventDatabase = get() database.sessionDao() } CommonModule val commonModule = module { single { Preference() } single { Network() } single { Resource() } factory { MutableConnectionLiveData() } factory<LocationService> { LocationServiceImpl(androidContext()) } } ApiModule val apiModule = module { single { val retrofit: Retrofit = get() retrofit.create(EventApi::class.java) } single { val retrofit: Retrofit = get() retrofit.create(AuthApi::class.java) } NetworkModule single { val connectTimeout = 15 // 15s val readTimeout = 15 // 15s val builder = OkHttpClient().newBuilder() .connectTimeout(connectTimeout.toLong(), TimeUnit.SECONDS) .readTimeout(readTimeout.toLong(), TimeUnit.SECONDS) .addInterceptor(HostSelectionInterceptor(get())) .addInterceptor(RequestAuthenticator(get())) .addNetworkInterceptor(StethoInterceptor()) if (BuildConfig.DEBUG) { val httpLoggingInterceptor = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY } builder.addInterceptor(httpLoggingInterceptor) } builder.build() } single { val baseUrl = BuildConfig.DEFAULT_BASE_URL val objectMapper: ObjectMapper = get() val onlineApiResourceConverter = ResourceConverter( objectMapper, Event::class.java, User::class.java, SignUp::class.java, Ticket::class.java, SocialLink::class.java, EventId::class.java, EventTopic::class.java, Attendee::class.java, TicketId::class.java, Order::class.java, AttendeeId::class.java, Charge::class.java, Paypal::class.java, ConfirmOrder::class.java, CustomForm::class.java, EventLocation::class.java, EventType::class.java, EventSubTopic::class.java, Feedback::class.java, Speaker::class.java, FavoriteEvent::class.java, Session::class.java, SessionType::class.java, MicroLocation::class.java, SpeakersCall::class.java, Sponsor::class.java, EventFAQ::class.java, Notification::class.java, Track::class.java, DiscountCode::class.java, Settings::class.java, Proposal::class.java) Retrofit.Builder() .client(get()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(JSONAPIConverterFactory(onlineApiResourceConverter)) .addConverterFactory(JacksonConverterFactory.create(objectMapper)) .baseUrl(baseUrl) .build() } As described in the code, Koin support single for creating a singleton object, factory for creating a new instance every time an object is injected. With all the modules created, it is really simple to get Koin running in the project with the function startKoin() and a few lines of code. We use it inside the application class: startKoin { androidLogger() androidContext(this@OpenEventGeneral) modules(listOf( commonModule, apiModule, viewModelModule, networkModule, databaseModule )) } Injecting created instances defined in the modules can be used in two way, directly inside…
