I know a similar question has been answered Here. But that was due to butter knife library problem but my case is different. In my case when I use dagger injected properties in my base activity it shows me error Caused by: kotlin.UninitializedPropertyAccessException: lateinit property pref has not been initialized
But the same property when I use in my sub activity (Login activity) it works fine.
eg. pref.setLanguage("abc") -> it works fine in login activity but throws error in base activity
Here is my code:
BaseActivity
abstract class BaseActivity : AppCompatActivity() { @Inject lateinit var pref: AppSharedPreferences @Inject lateinit var utils: Utils lateinit var mCurrentLanguage: String protected lateinit var progressBarUtils: ProgressBarUtils override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) progressBarUtils = ProgressBarUtils(this) mCurrentLanguage = "EN" pref.setSelectedLanguage(mCurrentLanguage) } }
LoginActivity
class LoginActivity : BaseActivity() { private val TAG = this.javaClass.name lateinit var loginViewModel: LoginViewModel @Inject lateinit var viewModelFactory: LoginViewModelFactory override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) AndroidInjection.inject(this) loginViewModel = ViewModelProviders.of(this, viewModelFactory).get( LoginViewModel::class.java) loadData("abc", "xyz") observerOnLoginResult() observerOnLoginError() } private fun observerOnLoginError() { loginViewModel.loginError().observe(this, Observer<String> { progressBarUtils.cancelProgressDialog() if (it != null) { Toast.makeText(this, resources.getString(R.string.error_message) + it, Toast.LENGTH_SHORT).show() } }) } private fun observerOnLoginResult() { loginViewModel.loginResult().observe(this, Observer<LoginModel> { progressBarUtils.cancelProgressDialog() if (it != null) { setData(it) } }) } private fun setData(loginData: LoginModel) { pref.setCurrentUserName(loginData.data.userName) } private fun loadData(email: String, password: String) { progressBarUtils.showProgressDialog() val builder = StringBuilder() var auth = Base64.encodeToString(("$email:$password").toByteArray(), Base64.NO_WRAP) builder.append("Basic ") builder.append(auth) loginViewModel.getLoginData(builder.toString()) } override fun onDestroy() { loginViewModel.disposeElements() super.onDestroy() }
AppModule
@Module class AppModule(val app: Application) { @Provides @Singleton fun provideApplication(): Application = app @Provides @Singleton fun provideSharedPreferences(): AppSharedPreferences = AppSharedPreferences(app) @Provides @Singleton fun provideUtils(): Utils = Utils(app) }
Builder Module
@Module abstract class BuildersModule { @PerActivity @ContributesAndroidInjector(modules = arrayOf(LoginModule::class)) abstract fun contributeLoginActivity(): LoginActivity @PerActivity abstract fun contributeBaseActivityActivity(): BaseActivity }
AppComponent
@Singleton @Component( modules = arrayOf(AndroidInjectionModule::class, AppModule::class, BuildersModule::class)) interface AppComponent { fun inject(app: LotusApp) }
If you try accessing Lateinit variables without initializing, it will throw an exception stating that it is not initialized or properly being accessed.
In order to avoid this situation, Kotlin introduced a new modifier called as "lateInit". Along with this modifier, Kotlin provides a couple of methods to check whether this variable is initialized or not. Use "lateInit" with a mutable variable. That means, we need use "var" keyword with "lateInit".
Accessing a lateinit property before it has been initialized throws a special exception that clearly identifies the property being accessed and the fact that it hasn't been initialized.
You can't use an object before you initialize it.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // prefs called in parents onCreate! setContentView(R.layout.activity_login) AndroidInjection.inject(this) // injection happens here
Get your calls in order. Easiest way to fix would be to move AndroidInjection.inject(this)
before the call to super.onCreate(...)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With