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