Monday, December 16, 2024

Kotlin Teacher

Kotlin Programming Language Best Tutorial Website

Kotlin Basics

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 

buildFeatures {
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

<uses-permission android:name=”android.permission.INTERNET”/>

1. Creating The Response Model Classes

We Need to Call 2 Rest Apis So We”ll   Create Two Response Model Classes

1.ItemGroupResponse(for Login Response And Return Data Structure Defining)
                                                                            2.LoginResponse(for Login Response And Return Data Structure Defining)
1.ItemGroupResponse
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
)
2. LoginResponse
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.
kotlin
@HiltAndroidApp
class MyApplication : Application()

2. @AndroidEntryPoint

  • Usage: Applied to Android components like Activity, Fragment, Service, or BroadcastReceiver.
  • Purpose: Marks an Android component to be injectable. It tells Hilt to generate code to provide the required dependencies for that component.
kotlin
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject 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.
kotlin
class SomeClass @Inject 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.
kotlin
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
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.
kotlin
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
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.
kotlin
@Singleton
class SomeRepository @Inject 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.
kotlin
@Module
@InstallIn(ActivityComponent::class)
object ActivityModule {
@Provides
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.
kotlin
class MyViewModel @ViewModelInject 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.
kotlin
@HiltViewModel
class MyViewModel @Inject 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.
kotlin
class MyAssistedClass @AssistedInject constructor(
@Assisted private val runtimeParameter: String
) {
@AssistedFactory
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
android:name=”.MyApplication” in  Application Tag in AndroidManifest.xml

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

@HiltViewModel

and Then

                                                                        And Also @Inject 
It is used to Inject The ApiService Dependency into ViewModel and It is Called Contructor Injection
After That We Have To Define Mutable  Data LateInt Variable of Type Val in  The ViewModel Class (Globally) After  Converting It To List .   Also Define Multable of The Error Message  as Val Variable Globally
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)




This is How We have to Get The Value of The Response
if Response is Coming as True the  Post The Value of Response and error Like This
itemGroupsLiveData.postValue(response.data)
and Also Like Messages & Error Shown Below
else {
errorMessage.postValue(response.message)
}
} catch (e: Exception) {
errorMessage.postValue(“Error: ${e.message}”)
}
Similarly in LoginViewModel 
@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

One thought on “Step By Step Guide How to Use Dagger Hilt Android Kotlin Project With Retrofit Api Call

  • 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.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *