lateinit property has not been initialized
Asked Answered
B

9

34

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)
Bowleg answered 21/10, 2016 at 11:54 Comment(0)
B
8

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 Views. 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.

Basie answered 23/5, 2017 at 2:23 Comment(0)
A
4

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.

Alicea answered 11/1, 2018 at 7:20 Comment(1)
this is the only correct solution, you probably will find ur self of with the compile "com.jakewharton:butterknife:8.8.1" but u will find ur gradle missing kapt "com.jakewharton:butterknife-compiler:8.8.1"Taurine
F
4

add apply plugin: 'kotlin-kapt' to the app level build.gradle file

example

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

and in dependencies section

implementation "com.jakewharton:butterknife:8.8.1"
kapt "com.jakewharton:butterknife-compiler:8.8.1"

Hope this Helps!

Forward answered 6/10, 2018 at 12:22 Comment(2)
I've found the following error at this point: :app:kaptGenerateStubsDebugKotlin -> The given artifact contains a string literal with a package reference 'android.support.v4.content' that cannot be safely rewritten. Libraries using reflection such as annotation processors need to be updated manually to add support for androidx.Tempest
I've solved it by following these instructions: github.com/JakeWharton/butterknifeTempest
G
2

Use Kotterknife for Butter Knife-esque View Binding for Kotlin.

Then you can bind your View with

val menuTitleTextView: CTextBasic by bindView(R.id.menu_title_text_view_id)
Gonna answered 21/10, 2016 at 12:30 Comment(3)
why dont use anko instead :PViolist
is KotterKnife a replacment for butter ? is it better i meanTrichoid
Library now deprecated with a warning — This was a terrible idea because it allocates an object for every view reference. Do not use, and do not use anything like it. Use view binding instead.Donitadonjon
W
2

In my case, I wasn't building ButterKnife correctly. Make sure you're importing its compiler in your module's build.gradle:

...
// Butter Knife
implementation "com.jakewharton:butterknife:$butterKnifeVersion"
kapt "com.jakewharton:butterknife-compiler:$butterKnifeVersion"
...

The discussion at Jetbrain's samples thread shed more light on this issue for me.

Another issue is that you might be accessing the views before the container has been created. Here is a related question, the discussion there is specific to kotlinx synthetic properties but same logic should apply to Butterknife view binding

Whinstone answered 18/3, 2018 at 9:58 Comment(0)
S
2

for me this error happens when include same layout several time

for example

 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <include layout="@layout/chart_bar_layout" />

 </LinearLayout>
 ...
 <include layout="@layout/chart_bar_layout" /> 

So find and remove that line make app work fine

Sverige answered 21/10, 2020 at 9:20 Comment(0)
C
0

There's a small trick you can try it by using Platform.runLater

 init {
        Platform.runLater {
        ....
        }
 }
Compile answered 23/8, 2020 at 15:42 Comment(0)
S
0

Faced this issue while, the problem was optional mark (?)

wrong: lateinit var temp_model: ArrayList<MyModel?>

Right: var temp_model = ArrayList< MyModel >()

Stenson answered 14/6, 2022 at 7:48 Comment(0)
G
-2

Your initializer block is not called. It only gets called when your primary constructor gets called. In your case, the secondary constructor gets used when view objects get created from xml layouts.

Change your init{...} block to fun init(){...} and call it as first statement in every constructor

You forgot to add the constructor

constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

=> add it and call init() in it

Gonna answered 21/10, 2016 at 13:14 Comment(3)
when I use this(ctx) it says Expression 'this' of type 'MenuItemView' cannot be invoked as a function. The function 'invoke()' is not foundBowleg
same problem, perhaps it is a bug, there is also opened issue on Jetbrains simple project github.com/JetBrains/kotlin-examples/issuesBowleg
secondary constructors call the primary constructor and init blocks execute. Some methods of instantiating a class may not call any constructor (they exist).Lynlyncean

© 2022 - 2024 — McMap. All rights reserved.