package com.example.myapp
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// Application initialization
}
}
package com.example.myapp.di
import com.example.myapp.data.repository.*
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindPostRepository(
impl: PostRepositoryImpl
): PostRepository
@Binds
@Singleton
abstract fun bindUserRepository(
impl: UserRepositoryImpl
): UserRepository
}
@Module
@InstallIn(SingletonComponent::class)
object DataModule {
@Provides
@Singleton
fun provideDatabase(
@ApplicationContext context: Context
): AppDatabase = AppDatabase.getDatabase(context)
@Provides
@Singleton
fun providePostDao(database: AppDatabase): PostDao =
database.postDao()
@Provides
@Singleton
fun provideCommentDao(database: AppDatabase): CommentDao =
database.commentDao()
}
package com.example.myapp.data.repository
import com.example.myapp.data.local.PostDao
import com.example.myapp.data.remote.ApiService
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton
interface PostRepository {
suspend fun fetchPosts(): Result<List<Post>>
fun observePosts(): Flow<List<Post>>
suspend fun getPost(id: Int): Result<Post>
suspend fun createPost(post: Post): Result<Post>
}
@Singleton
class PostRepositoryImpl @Inject constructor(
private val apiService: ApiService,
private val postDao: PostDao,
private val mapper: PostMapper
) : PostRepository {
override suspend fun fetchPosts(): Result<List<Post>> = try {
val response = apiService.getPosts()
val posts = response.posts
// Cache to database
postDao.insertAll(posts.map { mapper.toEntity(it) })
Result.success(posts)
} catch (e: Exception) {
// Return cached data on error
val cachedPosts = postDao.getAllPosts().map { mapper.fromEntity(it) }
if (cachedPosts.isNotEmpty()) {
Result.success(cachedPosts)
} else {
Result.failure(e)
}
}
override fun observePosts(): Flow<List<Post>> =
postDao.observePosts()
.map { entities -> entities.map { mapper.fromEntity(it) } }
override suspend fun getPost(id: Int): Result<Post> = try {
val response = apiService.getPost(id)
Result.success(response.post)
} catch (e: Exception) {
postDao.getPost(id)?.let {
Result.success(mapper.fromEntity(it))
} ?: Result.failure(e)
}
override suspend fun createPost(post: Post): Result<Post> = try {
val request = CreatePostRequest(
title = post.title,
body = post.body
)
val response = apiService.createPost(request)
postDao.insert(mapper.toEntity(response.post))
Result.success(response.post)
} catch (e: Exception) {
Result.failure(e)
}
}
class PostMapper @Inject constructor() {
fun toEntity(post: Post): PostEntity = PostEntity(
id = post.id,
title = post.title,
body = post.body,
authorId = post.authorId,
createdAt = post.createdAt,
likesCount = post.likesCount
)
fun fromEntity(entity: PostEntity): Post = Post(
id = entity.id,
title = entity.title,
body = entity.body,
authorId = entity.authorId,
createdAt = entity.createdAt,
likesCount = entity.likesCount
)
}
Hilt simplifies dependency injection in Android with compile-time code generation. I annotate Application class with @HiltAndroidApp and activities/fragments with @AndroidEntryPoint. Modules marked with @Module and @InstallIn define how to provide dependencies. @Provides methods in modules create instances, while @Binds connects interfaces to implementations. @Singleton ensures single instance app-wide. @ViewModelInject or @HiltViewModel injects ViewModels. Hilt handles scopes automatically—Activity, Fragment, View, ViewModel. Field injection uses @Inject on properties. Constructor injection is preferred for testability. Hilt integrates with Jetpack components and reduces boilerplate compared to Dagger.