I have a custom linearlayout class and when I want to create instance of this class, I get the following error:
lateinit property has not been initialized
I'm using the latest version of butterknife library.
The following is my Kotlin class:
class MenuItemView : LinearLayout { @BindView(R.id.menu_title_text_view_id) lateinit var menuTitleTextView : CTextBasic constructor(ctx: Context) : super(ctx) { } init { val view = LayoutInflater.from(context).inflate(R.layout.menu_item,this) ButterKnife.bind(this,view) } constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) { val menuAttrs = context.theme.obtainStyledAttributes(attrs, R.styleable.MenuItemView, 0, 0) try { val title: String = menuAttrs.getString(R.styleable.MenuItemView_menu_title) menuTitleTextView.text = title }catch (e : Exception){ e.printStackTrace() }finally { menuAttrs.recycle() } } fun setTitle( title : String){ menuTitleTextView.text = title } }
Error Log
kotlin.UninitializedPropertyAccessException: lateinit property menuTitleTextView has not been initialized at com.leavigstone.liberali.ui.custom.menu.MenuItemView.setTitle(MenuItemView.kt:48) at com.leavigstone.liberali.ui.activities.MainActivity.onAddButtonClick(MainActivity.java:142) at com.leavigstone.liberali.ui.activities.MainActivity_ViewBinding$3.doClick(MainActivity_ViewBinding.java:54) at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22) at android.view.View.performClick(View.java:4780) at android.view.View$PerformClick.run(View.java:19866) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5254) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
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 create a "lateInit" variable, we just need to add the keyword "lateInit" as an access modifier of that variable. Following are a set of conditions that need to be followed in order to use "lateInit" in Kotlin. Use "lateInit" with a mutable variable. That means, we need to use "var" keyword with "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". "lateInit" is only allowed with non-NULLable data types.
Kotlin lateinit – To declare non null Kotlin Variables without initialization, use lateinit keyword during declaration of the variable. Initialization of that variable could be done at a later point in code. Note : lateinit is supported from Kotlin 1.2. Make sure you are updated to latest Kotlin.
If you don't want to use any thirdparty libraries, you can add these extension functions (I tend to have a ContextExtensions.kt
or ViewExtensions.kt
for Context or View related extension functions), then put in it
inline fun <reified T : View> View.find(id: Int): T = findViewById(id) as T inline fun <reified T : View> Activity.find(id: Int): T = findViewById(id) as T inline fun <reified T : View> Fragment.find(id: Int): T = view?.findViewById(id) as T
these let you call find
from within Activity
, Fragment
, and View
s. So inside your class instead of
@BindView(R.id.menu_title_text_view_id) lateinit var menuTitleTextView : CTextBasic
you can have
val menuTitleTextView by lazy { find<CTextBasic>(R.id.menu_title_text_view_id) }
For things like UIs, it's better to val
instead of var
when they don't need to change. As a general rule in programming, try to keep things as immutable as possible, you would get far less bugs.
I found this works for me.
Change your build.gradle
in your project app
module.
dependencies { compile "com.jakewharton:butterknife:8.8.1" kapt "com.jakewharton:butterknife-compiler:8.8.1" }
use kapt
instead of annotationProcessor
.
and then you can do your familiar ButterKnife annotation like this:
class MainActivity : AppCompatActivity() { @BindView(R.id.myButton) lateinit var myButton: Button override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) ButterKnife.bind(this) //... } }
Enjoy.
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