Reduce memory footprint of Hilt (#159)

* Remove @Singleton where it is not needed

* Use @AssistedFactory where possible
This commit is contained in:
Kirill Kamakin
2023-07-04 18:22:16 +02:00
committed by GitHub
parent 2bc2bb76e4
commit 2375be0329
55 changed files with 51 additions and 215 deletions

View File

@@ -10,9 +10,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AddRecipeRepoImpl @Inject constructor(
private val addRecipeDataSource: AddRecipeDataSource,
private val addRecipeStorage: AddRecipeStorage,

View File

@@ -8,9 +8,7 @@ import gq.kirmanak.mealient.datasource.v0.models.CreateApiTokenRequestV0
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
import gq.kirmanak.mealient.datasource.v1.models.CreateApiTokenRequestV1
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AuthDataSourceImpl @Inject constructor(
private val serverInfoRepo: ServerInfoRepo,
private val v0Source: MealieDataSourceV0,

View File

@@ -8,9 +8,7 @@ import gq.kirmanak.mealient.logging.Logger
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AuthRepoImpl @Inject constructor(
private val authStorage: AuthStorage,
private val authDataSource: AuthDataSource,

View File

@@ -7,9 +7,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ServerInfoRepoImpl @Inject constructor(
private val serverInfoStorage: ServerInfoStorage,
private val versionDataSource: VersionDataSource,

View File

@@ -9,9 +9,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class VersionDataSourceImpl @Inject constructor(
private val v0Source: MealieDataSourceV0,
private val v1Source: MealieDataSourceV1,

View File

@@ -5,9 +5,7 @@ import gq.kirmanak.mealient.data.baseurl.ServerInfoStorage
import gq.kirmanak.mealient.data.storage.PreferencesStorage
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ServerInfoStorageImpl @Inject constructor(
private val preferencesStorage: PreferencesStorage,
) : ServerInfoStorage {

View File

@@ -3,17 +3,10 @@ package gq.kirmanak.mealient.data.configuration
import gq.kirmanak.mealient.BuildConfig
import gq.kirmanak.mealient.architecture.configuration.BuildConfiguration
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class BuildConfigurationImpl @Inject constructor() : BuildConfiguration {
@get:JvmName("_isDebug")
private val isDebug by lazy { BuildConfig.DEBUG }
override fun isDebug(): Boolean = BuildConfig.DEBUG
private val versionCode by lazy { BuildConfig.VERSION_CODE }
override fun isDebug(): Boolean = isDebug
override fun versionCode(): Int = versionCode
override fun versionCode(): Int = BuildConfig.VERSION_CODE
}

View File

@@ -6,9 +6,7 @@ import gq.kirmanak.mealient.logging.Logger
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class DisclaimerStorageImpl @Inject constructor(
private val preferencesStorage: PreferencesStorage,
private val logger: Logger,

View File

@@ -8,9 +8,7 @@ import gq.kirmanak.mealient.datastore.DataStoreModule.Companion.ENCRYPTED
import gq.kirmanak.mealient.logging.Logger
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
@Singleton
class From24AuthMigrationExecutor @Inject constructor(
@Named(ENCRYPTED) private val sharedPreferences: SharedPreferences,
private val authRepo: AuthRepo,

View File

@@ -5,9 +5,7 @@ import gq.kirmanak.mealient.data.storage.PreferencesStorage
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
import gq.kirmanak.mealient.logging.Logger
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class MigrationDetectorImpl @Inject constructor(
private val preferencesStorage: PreferencesStorage,
private val migrationExecutors: Set<@JvmSuppressWildcards MigrationExecutor>,
@@ -15,7 +13,6 @@ class MigrationDetectorImpl @Inject constructor(
private val logger: Logger,
) : MigrationDetector {
override suspend fun executeMigrations() {
val key = preferencesStorage.lastExecutedMigrationVersionKey

View File

@@ -13,9 +13,7 @@ import gq.kirmanak.mealient.datasource.v0.MealieDataSourceV0
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
import gq.kirmanak.mealient.model_mapper.ModelMapper
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class MealieDataSourceWrapper @Inject constructor(
private val serverInfoRepo: ServerInfoRepo,
private val v0Source: MealieDataSourceV0,

View File

@@ -4,9 +4,7 @@ import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
import gq.kirmanak.mealient.logging.Logger
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class RecipeImageUrlProviderImpl @Inject constructor(
private val serverInfoRepo: ServerInfoRepo,
private val logger: Logger,

View File

@@ -12,10 +12,8 @@ import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
import gq.kirmanak.mealient.logging.Logger
import gq.kirmanak.mealient.model_mapper.ModelMapper
import javax.inject.Inject
import javax.inject.Singleton
@OptIn(ExperimentalPagingApi::class)
@Singleton
class RecipeRepoImpl @Inject constructor(
private val mediator: RecipesRemoteMediator,
private val storage: RecipeStorage,

View File

@@ -4,9 +4,7 @@ import androidx.core.util.PatternsCompat
import gq.kirmanak.mealient.datasource.models.ParseRecipeURLInfo
import gq.kirmanak.mealient.logging.Logger
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ShareRecipeRepoImpl @Inject constructor(
private val logger: Logger,
private val parseRecipeDataSource: ParseRecipeDataSource,

View File

@@ -10,7 +10,6 @@ import gq.kirmanak.mealient.data.add.impl.AddRecipeRepoImpl
import gq.kirmanak.mealient.data.network.MealieDataSourceWrapper
import gq.kirmanak.mealient.datastore.recipe.AddRecipeStorage
import gq.kirmanak.mealient.datastore.recipe.AddRecipeStorageImpl
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
@@ -18,14 +17,11 @@ interface AddRecipeModule {
@Binds
@Singleton
fun provideAddRecipeRepo(repo: AddRecipeRepoImpl): AddRecipeRepo
@Binds
@Singleton
fun bindAddRecipeDataSource(mealieDataSourceWrapper: MealieDataSourceWrapper): AddRecipeDataSource
@Binds
@Singleton
fun bindAddRecipeStorage(addRecipeStorageImpl: AddRecipeStorageImpl): AddRecipeStorage
}

View File

@@ -27,6 +27,5 @@ interface AppModule {
}
@Binds
@Singleton
fun bindPreferencesStorage(preferencesStorage: PreferencesStorageImpl): PreferencesStorage
}

View File

@@ -6,13 +6,11 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import gq.kirmanak.mealient.architecture.configuration.BuildConfiguration
import gq.kirmanak.mealient.data.configuration.BuildConfigurationImpl
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
interface ArchitectureModule {
@Binds
@Singleton
fun bindBuildConfiguration(buildConfigurationImpl: BuildConfigurationImpl): BuildConfiguration
}

View File

@@ -1,12 +1,8 @@
package gq.kirmanak.mealient.di
import android.accounts.AccountManager
import android.content.Context
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import gq.kirmanak.mealient.data.auth.AuthDataSource
import gq.kirmanak.mealient.data.auth.AuthRepo
@@ -16,38 +12,23 @@ import gq.kirmanak.mealient.data.auth.impl.AuthRepoImpl
import gq.kirmanak.mealient.data.auth.impl.AuthStorageImpl
import gq.kirmanak.mealient.datasource.AuthenticationProvider
import gq.kirmanak.mealient.shopping_lists.repo.ShoppingListsAuthRepo
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
interface AuthModule {
companion object {
@Provides
@Singleton
fun provideAccountManager(@ApplicationContext context: Context): AccountManager {
return AccountManager.get(context)
}
}
@Binds
@Singleton
fun bindAuthDataSource(authDataSourceImpl: AuthDataSourceImpl): AuthDataSource
@Binds
@Singleton
fun bindAuthRepo(authRepo: AuthRepoImpl): AuthRepo
@Binds
@Singleton
fun bindAuthProvider(authRepo: AuthRepoImpl): AuthenticationProvider
@Binds
@Singleton
fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage
@Binds
@Singleton
fun bindShoppingListsAuthRepo(impl: AuthRepoImpl): ShoppingListsAuthRepo
}

View File

@@ -7,25 +7,20 @@ import dagger.hilt.components.SingletonComponent
import gq.kirmanak.mealient.data.baseurl.*
import gq.kirmanak.mealient.data.baseurl.impl.ServerInfoStorageImpl
import gq.kirmanak.mealient.datasource.ServerUrlProvider
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
interface BaseURLModule {
@Binds
@Singleton
fun bindVersionDataSource(versionDataSourceImpl: VersionDataSourceImpl): VersionDataSource
@Binds
@Singleton
fun bindBaseUrlStorage(baseURLStorageImpl: ServerInfoStorageImpl): ServerInfoStorage
@Binds
@Singleton
fun bindServerInfoRepo(serverInfoRepoImpl: ServerInfoRepoImpl): ServerInfoRepo
@Binds
@Singleton
fun bindServerUrlProvider(serverInfoRepoImpl: ServerInfoRepoImpl): ServerUrlProvider
}

View File

@@ -6,13 +6,11 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorage
import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorageImpl
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
interface DisclaimerModule {
@Binds
@Singleton
fun provideDisclaimerStorage(disclaimerStorageImpl: DisclaimerStorageImpl): DisclaimerStorage
}

View File

@@ -9,18 +9,15 @@ import gq.kirmanak.mealient.data.migration.From24AuthMigrationExecutor
import gq.kirmanak.mealient.data.migration.MigrationDetector
import gq.kirmanak.mealient.data.migration.MigrationDetectorImpl
import gq.kirmanak.mealient.data.migration.MigrationExecutor
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
interface MigrationModule {
@Binds
@Singleton
@IntoSet
fun bindFrom24AuthMigrationExecutor(from24AuthMigrationExecutor: From24AuthMigrationExecutor): MigrationExecutor
@Binds
@Singleton
fun bindMigrationDetector(migrationDetectorImpl: MigrationDetectorImpl): MigrationDetector
}

View File

@@ -15,36 +15,29 @@ import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
import gq.kirmanak.mealient.ui.recipes.images.RecipeModelLoaderFactory
import java.io.InputStream
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
interface RecipeModule {
@Binds
@Singleton
fun provideRecipeDataSource(mealieDataSourceWrapper: MealieDataSourceWrapper): RecipeDataSource
@Binds
@Singleton
fun provideRecipeRepo(recipeRepoImpl: RecipeRepoImpl): RecipeRepo
@Binds
@Singleton
fun bindImageUrlProvider(recipeImageUrlProviderImpl: RecipeImageUrlProviderImpl): RecipeImageUrlProvider
@Binds
@Singleton
fun bindModelLoaderFactory(recipeModelLoaderFactory: RecipeModelLoaderFactory): ModelLoaderFactory<RecipeSummaryEntity, InputStream>
@Binds
@Singleton
fun bindRecipePagingSourceFactory(recipePagingSourceFactoryImpl: RecipePagingSourceFactoryImpl): RecipePagingSourceFactory
companion object {
@Provides
@Singleton
fun provideGlideRequestOptions(): RequestOptions = RequestOptions.centerCropTransform()
.placeholder(R.drawable.placeholder_recipe)
}

View File

@@ -8,17 +8,14 @@ import gq.kirmanak.mealient.data.network.MealieDataSourceWrapper
import gq.kirmanak.mealient.data.share.ParseRecipeDataSource
import gq.kirmanak.mealient.data.share.ShareRecipeRepo
import gq.kirmanak.mealient.data.share.ShareRecipeRepoImpl
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
interface ShareRecipeModule {
@Binds
@Singleton
fun bindShareRecipeRepo(shareRecipeRepoImpl: ShareRecipeRepoImpl): ShareRecipeRepo
@Binds
@Singleton
fun bindParseRecipeDataSource(mealieDataSourceWrapper: MealieDataSourceWrapper): ParseRecipeDataSource
}

View File

@@ -5,31 +5,29 @@ import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.model.ModelCache
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.load.model.stream.BaseGlideUrlLoader
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import gq.kirmanak.mealient.data.recipes.impl.RecipeImageUrlProvider
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
import gq.kirmanak.mealient.logging.Logger
import kotlinx.coroutines.runBlocking
import java.io.InputStream
import javax.inject.Inject
import javax.inject.Singleton
class RecipeModelLoader private constructor(
class RecipeModelLoader @AssistedInject constructor(
private val recipeImageUrlProvider: RecipeImageUrlProvider,
private val logger: Logger,
concreteLoader: ModelLoader<GlideUrl, InputStream>,
cache: ModelCache<RecipeSummaryEntity, GlideUrl>,
@Assisted concreteLoader: ModelLoader<GlideUrl, InputStream>,
@Assisted cache: ModelCache<RecipeSummaryEntity, GlideUrl>,
) : BaseGlideUrlLoader<RecipeSummaryEntity>(concreteLoader, cache) {
@Singleton
class Factory @Inject constructor(
private val recipeImageUrlProvider: RecipeImageUrlProvider,
private val logger: Logger,
) {
@AssistedFactory
interface Factory {
fun build(
concreteLoader: ModelLoader<GlideUrl, InputStream>,
cache: ModelCache<RecipeSummaryEntity, GlideUrl>,
) = RecipeModelLoader(recipeImageUrlProvider, logger, concreteLoader, cache)
): RecipeModelLoader
}

View File

@@ -6,13 +6,14 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.ListPreloader
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.request.RequestOptions
import dagger.hilt.android.scopes.FragmentScoped
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
import gq.kirmanak.mealient.logging.Logger
import javax.inject.Inject
class RecipePreloadModelProvider(
private val adapter: PagingDataAdapter<RecipeSummaryEntity, *>,
class RecipePreloadModelProvider @AssistedInject constructor(
@Assisted private val adapter: PagingDataAdapter<RecipeSummaryEntity, *>,
private val fragment: Fragment,
private val requestOptions: RequestOptions,
private val logger: Logger,
@@ -28,15 +29,9 @@ class RecipePreloadModelProvider(
return Glide.with(fragment).load(item).apply(requestOptions)
}
@FragmentScoped
class Factory @Inject constructor(
private val fragment: Fragment,
private val requestOptions: RequestOptions,
private val logger: Logger,
) {
@AssistedFactory
interface Factory {
fun create(
adapter: PagingDataAdapter<RecipeSummaryEntity, *>,
) = RecipePreloadModelProvider(adapter, fragment, requestOptions, logger)
fun create(adapter: PagingDataAdapter<RecipeSummaryEntity, *>): RecipePreloadModelProvider
}
}

View File

@@ -20,10 +20,9 @@ class RecipeInfoFragment : BottomSheetDialogFragment() {
private val binding by viewBinding(FragmentRecipeInfoBinding::bind)
private val viewModel by viewModels<RecipeInfoViewModel>()
private lateinit var ingredientsAdapter: RecipeIngredientsAdapter
private val instructionsAdapter by lazy { recipeInstructionsAdapterFactory.build() }
@Inject
lateinit var recipeInstructionsAdapterFactory: RecipeInstructionsAdapter.Factory
lateinit var instructionsAdapter: RecipeInstructionsAdapter
@Inject
lateinit var recipeIngredientsAdapterFactory: RecipeIngredientsAdapter.Factory

View File

@@ -7,50 +7,38 @@ import androidx.core.view.isGone
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import gq.kirmanak.mealient.database.recipe.entity.RecipeIngredientEntity
import gq.kirmanak.mealient.databinding.ViewHolderIngredientBinding
import gq.kirmanak.mealient.logging.Logger
import gq.kirmanak.mealient.ui.recipes.info.RecipeIngredientsAdapter.RecipeIngredientViewHolder
import javax.inject.Inject
import javax.inject.Singleton
class RecipeIngredientsAdapter private constructor(
class RecipeIngredientsAdapter @AssistedInject constructor(
private val recipeIngredientViewHolderFactory: RecipeIngredientViewHolder.Factory,
private val logger: Logger,
private val disableAmounts: Boolean,
@Assisted private val disableAmounts: Boolean,
) : ListAdapter<RecipeIngredientEntity, RecipeIngredientViewHolder>(RecipeIngredientDiffCallback) {
@Singleton
class Factory @Inject constructor(
private val recipeIngredientViewHolderFactory: RecipeIngredientViewHolder.Factory,
private val logger: Logger,
) {
fun build(disableAmounts: Boolean) = RecipeIngredientsAdapter(
recipeIngredientViewHolderFactory = recipeIngredientViewHolderFactory,
logger = logger,
disableAmounts = disableAmounts,
)
@AssistedFactory
interface Factory {
fun build(disableAmounts: Boolean): RecipeIngredientsAdapter
}
class RecipeIngredientViewHolder private constructor(
private val binding: ViewHolderIngredientBinding,
class RecipeIngredientViewHolder @AssistedInject constructor(
@Assisted private val binding: ViewHolderIngredientBinding,
@Assisted private val disableAmounts: Boolean,
private val logger: Logger,
private val disableAmounts: Boolean,
) : RecyclerView.ViewHolder(binding.root) {
@Singleton
class Factory @Inject constructor(
private val logger: Logger,
) {
@AssistedFactory
interface Factory {
fun build(
binding: ViewHolderIngredientBinding,
disableAmounts: Boolean,
) = RecipeIngredientViewHolder(
binding = binding,
logger = logger,
disableAmounts = disableAmounts,
)
): RecipeIngredientViewHolder
}
fun bind(item: RecipeIngredientEntity) {
@@ -133,15 +121,18 @@ fun Double.mediantMethod(d: Int = 10, mixed: Boolean = true): Triple<Int, Int, I
n1 += n2
d2 = d + 1
}
d1 > d2 -> d2 = d + 1
else -> d1 = d + 1
}
break
}
x < m -> {
n2 += n1
d2 += d1
}
else -> {
n1 += n2
d1 += d2

View File

@@ -5,6 +5,9 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import gq.kirmanak.mealient.R
import gq.kirmanak.mealient.database.recipe.entity.RecipeInstructionEntity
import gq.kirmanak.mealient.databinding.ViewHolderInstructionBinding
@@ -12,21 +15,12 @@ import gq.kirmanak.mealient.extensions.resources
import gq.kirmanak.mealient.logging.Logger
import gq.kirmanak.mealient.ui.recipes.info.RecipeInstructionsAdapter.RecipeInstructionViewHolder
import javax.inject.Inject
import javax.inject.Singleton
class RecipeInstructionsAdapter private constructor(
class RecipeInstructionsAdapter @Inject constructor(
private val logger: Logger,
private val recipeInstructionViewHolderFactory: RecipeInstructionViewHolder.Factory,
) : ListAdapter<RecipeInstructionEntity, RecipeInstructionViewHolder>(RecipeInstructionDiffCallback) {
@Singleton
class Factory @Inject constructor(
private val logger: Logger,
private val recipeInstructionViewHolderFactory: RecipeInstructionViewHolder.Factory,
) {
fun build() = RecipeInstructionsAdapter(logger, recipeInstructionViewHolderFactory)
}
private object RecipeInstructionDiffCallback :
DiffUtil.ItemCallback<RecipeInstructionEntity>() {
override fun areItemsTheSame(
@@ -40,15 +34,14 @@ class RecipeInstructionsAdapter private constructor(
): Boolean = oldItem == newItem
}
class RecipeInstructionViewHolder private constructor(
private val binding: ViewHolderInstructionBinding,
class RecipeInstructionViewHolder @AssistedInject constructor(
@Assisted private val binding: ViewHolderInstructionBinding,
private val logger: Logger,
) : RecyclerView.ViewHolder(binding.root) {
@Singleton
class Factory @Inject constructor(private val logger: Logger) {
fun build(binding: ViewHolderInstructionBinding) =
RecipeInstructionViewHolder(binding, logger)
@AssistedFactory
interface Factory {
fun build(binding: ViewHolderInstructionBinding): RecipeInstructionViewHolder
}
fun bind(item: RecipeInstructionEntity, position: Int) {