可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a custom linearlayout class and when I want to create instance of this class, I got an error lateinit property has not been initialized
I'm using the latest version of butterknife library
this 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
}
}
this is 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)
回答1:
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.
回答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)
回答3:
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.
回答4:
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
回答5:
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 dependancies section
implementation "com.jakewharton:butterknife:8.8.1"
kapt "com.jakewharton:butterknife-compiler:8.8.1"
Hope this Helps!
回答6:
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