Step By Step Guide How to Use Dagger Hilt Android Kotlin Project With Retrofit Api Call
Step By Step Guide to Use Dagger Hilt in Android Using Kotlin Programming Language
Here Are The Steps to A Project In Android Kotlin Using Dagger Hilt
1. Add Libraries to The Project & Other Requirements to Gradle :-
After Creating a New Project In Android Studio Choosing Kotlin as Programming Language And Kotlin DSL as Gradle We Need To Add Libraries Into Our Project Which Are Listed Below:-
implementation("com.google.dagger:hilt-android:2.51.1") implementation("com.android.volley:volley:1.2.1") kapt("com.google.dagger:hilt-compiler:2.51.1") implementation("androidx.activity:activity-ktx:1.9.2") implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.appcompat:appcompat:1.7.0") implementation("com.google.android.material:material:1.12.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") testImplementation("junit:junit:4.13.2") implementation ("com.squareup.retrofit2:retrofit:2.9.0") implementation ("com.squareup.retrofit2:converter-gson:2.9.0") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1") implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.0") // Correct version androidTestImplementation("androidx.test.ext:junit:1.2.1") androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") To Enable ViewBinding add
viewBinding = true
}(just Below Comiple Sdk)
to App Level build.gradle File
Add The Below Plugins in App Level Gradle
plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id("kotlin-kapt") id("com.google.dagger.hilt.android") }
Adding The Necessary Permissions
add the following permission in AndroidManifest.xml
1. Creating The Response Model Classes
We Need to Call 2 Rest Apis So We”ll Create Two Response Model Classes
package com.example.kotlindi.Data data class ItemGroupResponse( val status: Boolean, val message: String, val data: List<ItemGroup> ) data class ItemGroup( val subCompanyId: String, val itemGroupId: String )
package com.example.kotlindi.Data data class LoginResponse( val status: Boolean, val message: String, val data: UserData? ) data class UserData( val userId: String, val password: String, val active: Int, val companyId: String, val roleId: String, val roleName: String, val name: String, val address: String, val gstNo: String, val loginType: String, val companyName: String, val companyAddress: String, val companyGstNo: String, val location: String )
2. For Defining Network Module
in This Class We”ll Define Our Api’s Base Url And Calling Api Service Class which contains The EndPoints of The Api And Also Adding Gson Parser For Parsing The Data
NetworkModule.kt
package com.example.kotlindi.Network import com.example.kotlindi.Services.ApiService import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) object NetworkModule { @Provides @Singleton fun provideRetrofit(): Retrofit { return Retrofit.Builder() .baseUrl("https://modern.readyroti.in/DealerDemand/webService_v1/") .addConverterFactory(GsonConverterFactory.create()) .build() } @Provides @Singleton fun provideApiService(retrofit: Retrofit): ApiService { return retrofit.create(ApiService::class.java) } } Here We Are Using Some Dependency Injection HILT Library . And Therefore Some Annotations Are Present Here Like @Provides
Dagger Hilt is a dependency injection (DI) framework for Android that simplifies the process of integrating Dagger into Android projects. Here are the key annotations used in Hilt for dependency injection:
1. @HiltAndroidApp
- Usage: Applied to the
Application
class. - Purpose: Triggers Hilt’s code generation, including the creation of the application-level component and its corresponding components. This annotation is required to set up the DI framework in your application.
class MyApplication : Application()
2. @AndroidEntryPoint
- Usage: Applied to Android components like
Activity
,Fragment
,Service
, orBroadcastReceiver
. - Purpose: Marks an Android component to be injectable. It tells Hilt to generate code to provide the required dependencies for that component.
class MainActivity : AppCompatActivity() {
lateinit var someDependency: SomeDependency
}
3. @Inject
- Usage: Applied to constructor parameters, fields, or methods.
- Purpose: Indicates that Hilt should provide the dependency for the annotated constructor or field. For constructors, it tells Hilt how to create instances of a class.
class SomeClass constructor(private val dependency: Dependency)
4. @Module
- Usage: Applied to a class that provides dependencies.
- Purpose: Marks a class as a module that can provide dependencies. Modules define methods annotated with
@Provides
to tell Hilt how to provide instances of certain types.
object NetworkModule {
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.example.com")
.build()
}
}
5. @Provides
- Usage: Applied to methods within a
@Module
. - Purpose: Tells Hilt how to create or provide an instance of a certain type. It’s used within modules to define how to provide dependencies.
object NetworkModule {
fun provideApiService(retrofit: Retrofit): ApiService {
return retrofit.create(ApiService::class.java)
}
}
6. @Singleton
- Usage: Applied to classes or methods within a module.
- Purpose: Indicates that Hilt should provide a single instance of the annotated class or method throughout the application lifecycle.
class SomeRepository constructor() {
// Implementation
}
7. @ComponentAndroidInjector
- Usage: Typically used internally by Hilt.
- Purpose: Defines a component that can inject dependencies into Android components. This is used by Hilt to generate the necessary components for dependency injection.
8. @InstallIn
- Usage: Applied to a module.
- Purpose: Specifies which Hilt component the module should be installed in, e.g.,
SingletonComponent
,ActivityComponent
,FragmentComponent
. This determines the lifespan and scope of the dependencies provided by the module.
object ActivityModule {
fun provideActivityScopedDependency(): SomeDependency {
return SomeDependency()
}
}
9. @ViewModelInject (Deprecated)
- Usage: Applied to
ViewModel
constructors. - Purpose: Tells Hilt how to provide dependencies to a
ViewModel
. This annotation has been replaced by@HiltViewModel
.
class MyViewModel constructor(private val repository: Repository) : ViewModel()
10. @HiltViewModel
- Usage: Applied to
ViewModel
classes. - Purpose: Indicates that Hilt should provide dependencies for the
ViewModel
. It replaces@ViewModelInject
and is used with@HiltAndroidApp
.
class MyViewModel constructor(private val repository: Repository) : ViewModel()
11. @AssistedInject
- Usage: Applied to constructors for classes that require assisted injection.
- Purpose: Used in combination with
@AssistedFactory
to handle cases where some parameters need to be provided at runtime, rather than compile time.
class MyAssistedClass constructor(
private val runtimeParameter: String
) {
interface Factory {
fun create(runtimeParameter: String): MyAssistedClass
}
}
These annotations help Hilt manage the lifecycle and provide the necessary dependencies to your Android components efficiently and effectively.
3. For Defining Service Class
Here We”ll Define The All Api Endpoints For Retrofit Api Call and Also Defining The Post Parameters if They Exist or Required
ApiService.kt
package com.example.kotlindi.Services import com.example.kotlindi.Data.ItemGroupResponse import com.example.kotlindi.Data.LoginResponse import retrofit2.http.Field import retrofit2.http.FormUrlEncoded import retrofit2.http.POST interface ApiService { @FormUrlEncoded @POST("login") suspend fun loginUser( @Field("userId") userId: String, @Field("password") password: String, @Field("appVersion") appVersion: String ): LoginResponse @FormUrlEncoded @POST("itemGroupList") suspend fun getItemGroupList( @Field("subCompanyId") subCompanyId: String, @Field("location") location: String ): ItemGroupResponse }
4. For Defining That We Are Creating A Project
This Kind of Class Is Required at the Root Level to Indicate that This App is a HiltAndroid App
package com.example.kotlindi import android.app.Application import dagger.hilt.android.HiltAndroidApp @HiltAndroidApp class MyApplication : Application() { } also define
5. Now Defining The ViewModel Classes to Call Api And get Data And Keep Data
Let Us Suppose We Need to Create ViewModel of Login The We will Create LoginViewModel
Like This
LoginViewModel.kt
package com.example.kotlindi.ViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.kotlindi.Data.LoginResponse import com.example.kotlindi.Services.ApiService import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class LoginViewModel @Inject constructor( private val apiService: ApiService ) : ViewModel() { private val _loginResult = MutableLiveData<LoginResponse>() val loginResult: LiveData<LoginResponse> = _loginResult fun loginUser(userId: String, password: String, appVersion: String) { viewModelScope.launch { try { val response = apiService.loginUser(userId, password, appVersion) _loginResult.postValue(response) } catch (e: Exception) { // Handle error, e.g. post error message e.printStackTrace() } } } }
As We Are Creating ViewModel While Using Hilt DI Framework we have to Use Annotation before the Class Name Using Annotation
and Then
fun fetchItemGroups(subCompanyId: String, location: String) { viewModelScope.launch { try { val response = apiService.getItemGroupList(subCompanyId, location) if (response.status) { itemGroupsLiveData.postValue(response.data) } else { errorMessage.postValue(response.message) } } catch (e: Exception) { errorMessage.postValue("Error: ${e.message}") } } } after That You Have to Create a api call method fetchitemgroups while passing two post params SubCompanyId and Location
val response = apiService.getItemGroupList(subCompanyId, location)
errorMessage.postValue(response.message)
}
} catch (e: Exception) {
errorMessage.postValue(“Error: ${e.message}”)
}
@HiltViewModel class LoginViewModel @Inject constructor( private val apiService: ApiService ) : ViewModel() { private val _loginResult = MutableLiveData<LoginResponse>() val loginResult: LiveData<LoginResponse> = _loginResult fun loginUser(userId: String, password: String, appVersion: String) { viewModelScope.launch { try { val response = apiService.loginUser(userId, password, appVersion) _loginResult.postValue(response) } catch (e: Exception) { e.printStackTrace() } } } } We"ll Add @HiltViewModel Before The viewModel ClassName to Make Sure That This ViewModel is Following The HiltPattern
I am not sure where you are getting your information, however great topic.
I must spend a while finding out much more or figuring out more.
Thank you for wonderful info I used to be looking for this info for my mission.