Android: ¿Cómo hacer la inyección de componente de daga multimodulo?
Tengo androide gradle multi-module
dagger
aplicación.
Dentro de cada módulo Estoy haciendo inyección a través de su propio componente como este:
MainApp.appComponent.inject(this)
para el módulo :app
y
BaseApp.appComponent.inject(this)
para el módulo :app:base
.
Ahora tratando de hacer SharedPreferences
envoltura disponible dentro app:base
módulo. Hasta este punto todo funcionó bien, pero después de esto me enfrenté a este error
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.alazar.tracker/com.alazar.tracker.MainActivity}: kotlin.UninitializedPropertyAccessException: lateinit property appComponent has not been initialized
Application.name
propiedad especificada en Manifest.xml del :app:base
módulo.
¿Qué estoy haciendo mal y cómo arreglar eso? Gracias por cualquier sugerencia.
MainActivity:
class MainActivity : BaseActivity(), View.OnClickListener {
@Inject
lateinit var userManager: UserManagerInterface
@Inject
lateinit var preferences: PreferenceProvider
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MainApp.appComponent.inject(this)
binding = ActivityMainBinding.inflate(layoutInflater)
binding.btnSignOut.setOnClickListener(this)
binding.btnStart.setOnClickListener(this)
binding.btnStop.setOnClickListener(this)
if (!userManager.isAuthenticated()) {
openPostActivity.launch(Intent(this, AuthActivity::class.java))
} else {
setContentView(binding.root)
changeStatus(preferences.getServiceStatus())
}
}
}
MainApp:
@MainScope
@Component(
dependencies = [
],
modules = [
MainModule::class,
]
)
interface MainAppComponent {
fun inject(activity: MainActivity)
fun inject(activity: MapActivity)
}
@Module(
includes = [
AuthUserModule::class,
BaseModule::class,
]
)
class MainModule
class MainApp : Application() {
override fun onCreate() {
super.onCreate()
appComponent = DaggerMainAppComponent
.builder()
.build()
}
companion object {
lateinit var appComponent: MainAppComponent
}
}
BaseApp:
@Singleton
@Component(
modules = [
BaseModule::class,
]
)
interface BaseComponent {
fun inject(baseApp: BaseApp)
fun inject(wrapper: SharedPrefWrapper)
}
@Module
class BaseModule constructor(private val application: Application) {
@Provides
fun provideContext() : Context = application.applicationContext
@Provides
fun provideSharedPreferences() : PreferenceProvider = SharedPrefWrapper(application.applicationContext)
}
class BaseApp : Application() {
override fun onCreate() {
super.onCreate()
appComponent = DaggerBaseComponent
.builder()
.baseModule(BaseModule(this))
.build()
}
companion object {
lateinit var appComponent: BaseComponent
}
}
Envoltorio de preferencias compartido
class SharedPrefWrapper @Inject constructor(private val context: Context) : PreferenceProvider {
init {
BaseApp.appComponent.inject(this)
Log.d("************ CONTEXT", context.toString())
}
private var preferences: SharedPreferences = context.getSharedPreferences(
context.getString(R.string.shared_preference_name),
AppCompatActivity.MODE_PRIVATE
)
override fun saveServiceStatus(status: Boolean) {
val editor = preferences.edit()
editor.putBoolean(context.getString(R.string.preference_service_param), status)
editor.apply()
}
override fun getServiceStatus(): Boolean {
return preferences.getBoolean(context.getString(R.string.preference_service_param), false)
}
}
Pregunta hecha hace 3 años, 5 meses, 0 días - Por codecrusaderx58e2
2 Respuestas:
-
El error que estás experimentando ("java.lang.RuntimeException: Unable to start activity ComponentInfo{com.alazar.tracker/com.alazar.tracker.MainActivity}: kotlin.UninitializedPropertyAccessException: lateinit property appComponent has not been initialized") se debe a que estás intentando acceder a la propiedad
appComponent
deBaseApp
oMainApp
antes de que haya sido inicializada.La solución a este problema es asegurarte de que las instancias de
BaseAppComponent
yMainAppComponent
sean inicializadas previamente antes de hacer la inyección en las clases que las requieran.En el caso de
SharedPrefWrapper
, estás intentando hacer la inyección en el constructor a través deBaseApp.appComponent.inject(this)
. Para asegurarte de queBaseApp.appComponent
esté inicializada previamente, puedes mover la inyección a un método separado y llamar a ese método cuando la inyección sea realmente necesaria.Por ejemplo, podrías modificar tu clase
SharedPrefWrapper
de la siguiente manera:kotlin class SharedPrefWrapper @Inject constructor(private val context: Context) : PreferenceProvider { private var preferences: SharedPreferences init { preferences = context.getSharedPreferences( context.getString(R.string.shared_preference_name), AppCompatActivity.MODE_PRIVATE ) } fun inject() { BaseApp.appComponent.inject(this) Log.d("NoneNoneNone CONTEXT", context.toString()) } override fun saveServiceStatus(status: Boolean) { val editor = preferences.edit() editor.putBoolean(context.getString(R.string.preference_service_param), status) editor.apply() } override fun getServiceStatus(): Boolean { return preferences.getBoolean(context.getString(R.string.preference_service_param), false) } }
Y luego, en tu clase
BaseApp
, puedes llamar al métodoinject()
después de queBaseAppComponent
se haya construido:kotlin class BaseApp : Application() { override fun onCreate() { super.onCreate() appComponent = DaggerBaseComponent .builder() .baseModule(BaseModule(this)) .build() // Llamar al método inject de SharedPrefWrapper SharedPrefWrapper(applicationContext).inject() } companion object { lateinit var appComponent: BaseComponent } }
De esta manera, te aseguras de que
BaseAppComponent
esté inicializado antes de realizar la inyección enSharedPrefWrapper
. Asegúrate de aplicar un enfoque similar en otros lugares donde se realicen inyecciones de componentes en tu código.Respondida el Dec 18, 2020 a las 19:03 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
Problema:
El error que estás encontrando se debe a que la propiedad
appComponent
enMainActivity
no se está inicializando correctamente. Esto se debe a que la llamada aMainApp.appComponent.inject(this)
se está realizando antes de queMainApp
se haya inicializado.Solución:
Para solucionar este problema, puedes mover la llamada a
MainApp.appComponent.inject(this)
al métodoonAttach()
deMainActivity
, que se llama después de que se haya creado la instancia de la actividad.MainActivity modificada:
kotlin class MainActivity : BaseActivity(), View.OnClickListener { @Inject lateinit var userManager: UserManagerInterface @Inject lateinit var preferences: PreferenceProvider private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) changeStatus(preferences.getServiceStatus()) } override fun onAttach() { super.onAttach() MainApp.appComponent.inject(this) } ... }
Nota:
También es importante asegurarse de que la aplicación se está inicializando correctamente en
BaseApp
. En particular, debes asegurarte de queBaseModule(this)
se esté pasando al crearBaseComponent
.BaseApp modificada:
kotlin class BaseApp : Application() { override fun onCreate() { super.onCreate() appComponent = DaggerBaseComponent .builder() .baseModule(BaseModule(this)) .build() } ... }
Otras recomendaciones:
Considera utilizar la anotación
@AndroidEntryPoint
enMainActivity
para simplificar la inyección de componentes. Divide tu base de datos en módulos más pequeños para mejorar la modularidad y la mantenibilidad.- Utiliza herramientas como Hilt o Koin para simplificar aún más la inyección de dependencias.
Espero que esto solucione tu problema. Avísame si tienes alguna otra pregunta.
Respondida el Dec 18, 2020 a las 19:09 - por Gemini
Votos positivos: 0 | Votos negativos: 0