I searched among many similar SharedPreferences questions, but couldn't apply to my project. It's a RuntimeException which requires a SharedPreferences lateinit variable to be initialised.
Error Message:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.me.tabuild3/com.me.tabuild3.Tutorial}: kotlin.UninitializedPropertyAccessException: lateinit property mPref has not been initialized
(...)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property mPreferences has not been initialized
at com.me.tabuild3.Z3Preferences.<init>(Z3Preferences.kt:15)
at com.me.tabuild3.Tutorial.onCreate(Tutorial.kt:15)
This is Tutorial.kt, which triggers the error:
class Tutorial : AppCompatActivity() {
val binding by lazy {
B00TutorialBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.b00_tutorial)
val fragmentList = listOf(Z0A(), Z1B(), Z3Preferences()) // the 15th line is here
val adapter = Z99FragmentAdapter(this)
adapter.fragmentList = fragmentList
binding.tutorialPager.adapter = adapter
binding.tutorialPager.currentItem = 1
}
}
This activity loads three fragments, and the third one, Z3Preferences(), edits SharedPreferences to modify things(At least I plan so).
This is Z3Preferences, which holds actual(?) error:
class Z3Preferences : Fragment() {
lateinit var binding: F04PrefBinding
private lateinit var mPref: SharedPreferences // seems this thing has to be initialised
val preferencesEditor: SharedPreferences.Editor = mPref.edit() // same error message for this line when the upper solved(?)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = F04PrefBinding.inflate(inflater, container, false)
return binding.root
}
override fun onResume() {
super.onResume()
binding.radioGroupTextSize.setOnCheckedChangeListener { group, checkedId ->
when (checkedId) {
R.id.textSize_RB1 -> preferencesEditor.putInt("TXTSZ", 12)
R.id.textSize_RB2 -> preferencesEditor.putInt("TXTSZ", 14)
R.id.textSize_RB3 -> preferencesEditor.putInt("TXTSZ", 16)
R.id.textSize_RB4 -> preferencesEditor.putInt("TXTSZ", 18)
R.id.textSize_RB5 -> preferencesEditor.putInt("TXTSZ", 20)
}
}
binding.radioGroupTextSpeed.setOnCheckedChangeListener { group, checkedId ->
when (checkedId) {
R.id.textSpd_RB1 -> {
preferencesEditor.putInt("TXTSP", 160)
preferencesEditor.putBoolean("TXTAN", true)
}
R.id.textSpd_RB2 -> {
preferencesEditor.putInt("TXTSP", 120)
preferencesEditor.putBoolean("TXTAN", true)
}
R.id.textSpd_RB3 -> {
preferencesEditor.putInt("TXTSP", 80)
preferencesEditor.putBoolean("TXTAN", true)
}
R.id.textSpd_RB4 -> {
preferencesEditor.putInt("TXTSP", 40)
preferencesEditor.putBoolean("TXTAN", true)
}
R.id.textSpd_RB5 -> {
preferencesEditor.putInt("TXTSP", 40)
preferencesEditor.putBoolean("TXTAN", false)
}
}
}
}
override fun onPause() {
super.onPause()
preferencesEditor.apply()
}
}
So.. How do I initialise the lateinit var mPref? I'm totally lost at this point and similar questions have different app construction and I couldn't get the idea.
So.. How do I initialise the lateinit var mPref?
You set it to some valid value, usually as early as possible. On Android, this usually means doing so in onCreate
or onCreateView
. But at least before anything tries to access it. You can do this in your onCreateView
:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mPref = // get preferences in your prefered way
binding = F04PrefBinding.inflate(inflater, container, false)
return binding.root
}
it shoots the same error for the next line(I marked on the code in the post): "lateinit property mPref has not been initialized", but at the next line! How do I do this?
You are trying to use an unintialized lateinit
variable immediately after declaring it:
private lateinit var mPref: SharedPreferences // Declared but not initialized
val preferencesEditor: SharedPreferences.Editor = mPref.edit() // Immediately attemps to use mPref which is not initialized (during constructor call)
You need to not try to initialize the editor immediately like that.
You can either make it a property, so it only tries to access mPref when accessed and not during constructor call, which assumes it'll be valid by the time you try to access the editor:
val preferencesEditor: SharedPreferences.Editor get() = mPref.edit()
Or, you could make the editor itself a lateinit
property and initialize it later:
lateinit var preferencesEditor: SharedPreferences.Editor
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mPref = // get preferences in your prefered way
preferencesEditor = mPref.edit()
binding = F04PrefBinding.inflate(inflater, container, false)
return binding.root
}
Please check the documentation for how lateinit and kotlin constructors work.