I am trying to implement the latest version of Dagger2 in a Single-Activity app, but it is not known why, when initializing my starting activity, Dagger2 does not inject dependencies, I has a
fatal error in my base activity : Unable to resume activity kotlin.UninitializedPropertyAccessException: lateinit property navigatorHolder has not been initialized
here is my code
AppComponent:
#Singleton
#Component(modules = [
AndroidSupportInjectionModule::class,
ActivityInjectionModule::class,
ActivityProviderModule::class,
AndroidInjectionModule::class,
NetworkModule::class,
RemoteModule::class,
NavigationModule::class,
ParserModule::class,
CacheModule::class])
interface AppComponent : AndroidInjector<App> {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
#BindsInstance
fun context(context: Context) : Builder
fun build(): AppComponent
}
override fun inject(app: App)
}
App:
class App : DaggerApplication(){
private val applicationInjector =
DaggerAppComponent.builder().application(this).context(this).build()
override fun applicationInjector(): AndroidInjector<out DaggerApplication> =
applicationInjector
companion object {
lateinit var cicerone: Cicerone<Router>
private set
}
override fun onCreate() {
super.onCreate()
cicerone = Cicerone.create()
initAppComponent()
initStetho()
Timber.plant(Timber.DebugTree())
}
AppActivity:
class AppActivity : MvpAppCompatActivity() , HasAndroidInjector, RouterProvider {
#Inject
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
#Inject
lateinit var mainActivityProvider: ActivityProvider
#Inject
lateinit var navigatorHolder: Lazy<NavigatorHolder>
#Inject
override lateinit var ciceroneRouter: Router
override fun androidInjector(): AndroidInjector<Any> = dispatchingAndroidInjector
private val navigator : Navigator by lazy {
CustomSupportAppNavigator(this, supportFragmentManager, R.layout.activity_main)
}
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
AndroidInjection.inject(this)
mainActivityProvider.acitvity = this
Timber.e("onCreate AppActivity")
super.onCreate(savedInstanceState, persistentState)
setContentView(R.layout.activity_main)
initBottomBar()
}
override fun onResumeFragments() {
super.onResumeFragments()
navigatorHolder.get().setNavigator(navigator)
}
ActivityInjectionModule
#Module(includes = [AndroidInjectionModule::class])
interface ActivityInjectionModule {
#ContributesAndroidInjector(
modules = [FragmentInjectionModule::class]
)
fun activityInjector() : AppActivity
}
NavigationModule
#Module
class NavigationModule {
#Provides
#Singleton
fun provideRouter() = App.cicerone.router
#Provides
#Singleton
fun provideNavigatorHolder() : NavigatorHolder {
return App.cicerone.navigatorHolder
}
#Provides
#Singleton
fun provideLocalNavigationHolder(): LocalCiceroneHolder {
return LocalCiceroneHolder()
}
}
Also i post android:name=".App" inandroid manifest.
I have tried many different options already, but I still cannot find the reason
Can you change your App to like this and try again:
class App : DaggerApplication(){
private val appComponent =
DaggerAppComponent.builder().application(this).context(this).build().inject(this)
companion object {
lateinit var cicerone: Cicerone<Router>
private set
}
override fun onCreate() {
super.onCreate()
cicerone = Cicerone.create()
initAppComponent()
initStetho()
Timber.plant(Timber.DebugTree())
}
Also remove AndroidInjector<App> from AppComponent
Related
Some users have crashes, at what point they occur and for what reason it is not yet clear.
Logs (Firebase Crashlytics)
Fatal Exception: fu.p
lateinit property factory has not been initialized
com.its.yarus.base.BaseFragment.getFactory (BaseFragment.java:7)
com.its.yarus.ui.search.SearchTypeFragment$vm$3.invoke (SearchTypeFragment.java:1)
androidx.lifecycle.ViewModelLazy.getValue (ViewModelLazy.java:1)
com.its.yarus.ui.search.SearchTypeFragment.getVm (SearchTypeFragment.java:2)
com.its.yarus.ui.search.SearchTypeFragment.update$lambda-2 (SearchTypeFragment.java:5)
androidx.camera.camera2.internal.Camera2CameraControlImpl$$InternalSyntheticLambda$7$e9d410b43813df60e795612fb2f87f0233ac603a6d2ad492f8d3b620f6813f78$0.run$bridge (Camera2CameraControlImpl.java:5)
BaseFragment
abstract class BaseFragment: Fragment() {
#Inject
lateinit var uploadManager: UploadManager
#Inject
lateinit var factory: ViewModelFactory
#Inject
lateinit var ciceroneHolder: LocalCiceroneHolder
abstract var fragmentName: String
}
BaseMainFragment
....
override fun onCreate(savedInstanceState: Bundle?) {
YarusApp.component?.inject(this)
super.onCreate(savedInstanceState)
}
....
SearchTypeFragment
class SearchTypeFragment : BaseRecyclerFragment(), NotTopInset {
override val vm by viewModels<SearchViewModel>(
ownerProducer = { this },
factoryProducer = { factory }
)
private val vmSearch by viewModels<SearchMainViewModel>(
ownerProducer = { requireParentFragment() },
factoryProducer = { factory }
)
}
Inheritance chain:
SearchTypeFragment (located in the ViewPager) у SearchFragment ->
BaseRecyclerFragment ->
BaseMainFragment ->
BaseFragment
when passing the factory variable, the crash occurs
ViewModelFactory
#Singleton
class ViewModelFactory #Inject constructor(private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
val viewModelProvider = viewModels[modelClass]
?: throw IllegalArgumentException("model class $modelClass not found")
return viewModelProvider.get() as T
}
}
ViewModelModule
#Module
abstract class ViewModelModule {
#Binds
#Singleton
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}
MainComponent
#Singleton
#Component(
modules = [
AndroidSupportInjectionModule::class,
NetworkModule::class,
RepositoryModule::class,
ApplicationModule::class,
ViewModelModule::class,
RoomModule::class,
NavigationModule::class,
SocketModule::class,
ServiceModule::class,
ExoPlayerModule::class
]
)
interface MainComponent {
fun inject(application: YarusApp)
fun inject(activity: BaseActivity)
fun inject(activity: OnBoardingActivity)
fun inject(activity: SignInActivity)
fun inject(fragment: BaseFragment)
fun inject(fragment: BaseSignInFragment)
fun inject(fragment: BaseOnboardingFragment)
fun inject(fragment: BaseDialogFragment)
fun inject(fragment: BaseMusicFragment)
fun inject(service: CloudMessagingService)
fun inject(service: PlayerService)
fun inject(seance: SeanceBottomSheet)
fun inject(seance: PlaceBottomSheet)
fun inject(promo: PromoBottomSheet)
fun inject(bottomSheet: BaseBottomSheetDialogFragment)
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): MainComponent
}
}
Application
class YarusApp : Application() {
override fun onCreate() {
super.onCreate()
component = DaggerMainComponent.builder().application(this).build()
component?.inject(this)
}
companion object {
var component: MainComponent? = null
}
}
Do you have any ideas or suggestions on how to fix this problem?
When I try to inject app crashing with lateinit property ... has not been initialized exception. I understand I have to inject my app into graph, but I do not succeed in that. What is the best way to do this?
class App : Application() {
#Inject
lateinit var localeManager: Lazy<LocaleManager>
val appComponent: AppComponent by lazy {
DaggerAppComponent.factory().create(applicationContext)
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(localeManager.get().setLocale(base))
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
localeManager.get().setLocale(this)
}
}
#Singleton
#Component(modules = [NetworkModule::class, AppSubcomponents::class])
interface AppComponent {
#Component.Factory
interface Factory {
fun create(#BindsInstance context: Context): AppComponent
}
fun registrationComponent(): RegistrationComponent.Factory
fun lobbyComponent(): PropertyComponent.Factory
fun supplierComponent(): SupplierComponent.Factory
fun notificationComponent(): NotificationComponent.Factory
fun serviceComponent(): ServiceComponent.Factory
fun settingsComponent() : SettingsComponent.Factory
fun cardComponent() : CardComponent.Factory
fun inject(activity: MainActivity)
}
class LocaleManager #Inject constructor(val storage: UserStorage) {
//some code
}
I'm using dagger 2.25.2 and androidx.lifecycle for dependency injection in my android project. But I've got error ViewModelFactory has not been initialized
Here is my code's
class PropertyActivity : AppCompatActivity() {
#Inject
lateinit var propertyViewModelFactory: PropertyViewModelFactory
lateinit var propertyViewModel: PropertyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.property_activity)
propertyViewModel = ViewModelProviders.of(this, propertyViewModelFactory).get(
PropertyViewModel::class.java)
propertyViewModel.loadProperties()
}
ViewModelFactory:
class PropertyViewModelFactory #Inject constructor(
private val propertyViewModel: PropertyViewModel) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(PropertyViewModel::class.java!!)) {
return propertyViewModel as T
}
throw IllegalArgumentException("Unknown class name")
}
}
AppModule:
#Module
class AppModule(val app: Application){
#Provides
#Singleton
fun provideApplication(): Application = app
#Provides
#Singleton
fun providePropertyViewModelFactory(factory: PropertyViewModelFactory): ViewModelProvider.Factory = factory
}
BuildersModule:
#Module
abstract class BuildersModule {
#ContributesAndroidInjector
abstract fun contributePropertyActivity(): PropertyActivity
}
AppComponent:
#Singleton
#Component(modules = arrayOf(AndroidInjectionModule::class,BuildersModule::class, AppModule::class))interface PlotComponent {
fun inject(app: Application)
}
Application Class :
class PlotApplication : Application(), HasAndroidInjector {
#Inject
lateinit var activityInjector: DispatchingAndroidInjector<Any>
override fun onCreate() {
super.onCreate()
DaggerPlotComponent.builder()
.appModule(AppModule(this))
.build().inject(this)
}
override fun androidInjector(): AndroidInjector<Any> = activityInjector
}
I doesn't see where you inject dependency in your activity. The problem may be in this.
Add
AndroidInjection.inject(this)
in your onCreate
I have problems when starting Dagger in Android project with Kotlin.
This estructure is the next one
Dagger is included in an Android module that is called by the client application
MagicBox.kt
interface MagicBox {
fun getDate(): Long?
}
MagicBoxImpl.kt
class MagicBoxImpl (): MagicBox{
var date: Long = Date().time
override fun getDate(): Long {
return date
}
}
MainModule.kt
#Module
class MainModule (private val app: Application) {
#Provides
#Singleton
fun provideMagicBox(): MagicBox {
return MagicBoxImpl()
}
}
MainComponent.kt
#Singleton
#Component(modules = [MainModule::class, PresenterModule::class])
interface MainComponent{
fun inject(target: Activity)
}
Application.kt
class Application: Application() {
lateinit var mainComponent: MainComponent
override fun onCreate() {
super.onCreate()
mainComponent = initDagger(this)
}
private fun initDagger(app: Application): MainComponent =
DaggerMainComponent.builder()
.mainModule(MainModule(app))
.build()
}
MainActivity.kt
#Inject
lateinit var magicBox: MagicBox
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_layout)
(application as ClientSdk).mainComponent.inject(this)
tvDaggerTest = findViewById(R.id.tvDaggerTest)
tvDaggerTest!!.text = magicBox.getDate().toString()
}
Get the following error
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property magicBox has not been initialized
fun inject(target: Activity) should be fun inject(target: MainActivity)
Also for better Dagger usage, the following should be:
#Module
abstract class MainModule {
#Binds
abstract fun magicBox(impl: MagicBoxImpl): MagicBox
}
and
#Singleton class MagicBoxImpl #Inject constructor(): MagicBox {
I'm trying to implement mvp pattern with dagger 2 support in my app
Here's the objects:
class BaseApplication : Application(), HasActivityInjector
{
override fun onCreate()
{
super.onCreate()
initDi()
}
private fun initDi(){
DaggerAppComponent.builder().application(this).build().inject(this)
}
#Inject lateinit var activityInjector: DispatchingAndroidInjector<Activity>
override fun activityInjector(): AndroidInjector<Activity>
{
return activityInjector
}
}
#Singleton
#Component(modules = arrayOf(AndroidInjectionModule::class, AppModule::class, ActivityBuilder::class))
interface AppComponent
{
#Component.Builder
interface Builder
{
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
fun inject(app: BaseApplication)
}
#Module
class AppModule
{
#Provides
#Singleton
internal fun provideContext(application: Application): Context
{
return application
}
}
#Module
abstract class ActivityBuilder
{
#ContributesAndroidInjector(modules = arrayOf(LoginFragmentProvider::class))
internal abstract fun bindAuthenticationActivity(): AuthenticationActivity
}
#Module
public abstract class LoginFragmentProvider
{
#ContributesAndroidInjector
abstract LoginFragment provideLoginFragmentFactory();
}
class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector
{
#Inject lateinit var androidInjector: DispatchingAndroidInjector<Fragment>
override fun supportFragmentInjector(): AndroidInjector<Fragment>
{
return androidInjector
}
}
class LoginFragment : Fragment() {
override fun onAttach(context: Context?)
{
AndroidSupportInjection.inject(this)
super.onAttach(context)
}
The problem is, when login fragment calls AndroidSupportInjection.inject(this), The AuthenticationActivity supportFragmentInjector get called, but the androidInjector is still null
As a result, I'm getting the exception:
java.lang.RuntimeException: Unable to start activity .....AuthenticationActivity}: kotlin.UninitializedPropertyAccessException: lateinit property androidInjector has not been initialized
I'm not sure how to fix this
Thanks in advance
I think you forget to inject your AuthenticationActivity. You should call AndroidInjection in onCreate.
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
}
Edit: You can check my example repo for more information. https://github.com/savepopulation/dc-tracker