I have that small project as example:
MainActivity.kt
package com.example.scratch
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.scratch.CustomViewWithContent
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
CustomViewWithContainer.kt
package com.example.scratch
import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout
open class CustomViewWithContainer : ConstraintLayout {
private val contentContainer by lazy {
findViewById<FrameLayout>(R.id.content_container)
}
constructor(context: Context?) : super(context) {
commonInit(context)
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
commonInit(context)
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
commonInit(context)
}
protected open fun commonInit(context: Context?) {
if (context == null) {
return
}
inflate(context, R.layout.custom_view_with_container, this)
if (isInEditMode) {
return
}
}
protected fun setContent(contentView: View) {
contentContainer.removeAllViews()
contentContainer.addView(contentView)
(contentView.layoutParams as FrameLayout.LayoutParams).gravity = Gravity.CENTER
}
}
layout/custom_view_content.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is a text view" />
</FrameLayout>
CustomViewWithContent.kt
package com.example.scratch
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.TextView
class CustomViewWithContent : CustomViewWithContainer {
private lateinit var contentView: View
private val textView by lazy {
contentView.findViewById<TextView>(R.id.text_view)
}
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
override fun commonInit(context: Context?) {
super.commonInit(context)
if (context == null) {
return
}
contentView = inflate(context, R.layout.custom_view_content, null)
if (isInEditMode) {
return
}
setContent(contentView)
Log.d(
CustomViewWithContent::class.java.simpleName,
"TextView id: ${textView.id}"
)
}
}
layout/custom_view_with_container
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<FrameLayout
android:id="@+id/content_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</merge>
But when I run it, it crashes, displaying the following log:

And I don't know why it is crashing. The id of the view that I am fetching is exactly equals to the one that can be found in the layout .xml.
I would love to know the reason why the lazy is returning null instead of the view itself, because it makes no sense :/
Through that gif, we can see that:
textView(which is alazy val) is considered as null;notNullTextViewis not null, and it runs the same code found inside thetext viewlazy val initialization block;- running the same initilization code of the
textViewin the Watches of the IDE, it also returns null.
