Q:

How to initialize and use UI elements

I am currently working on my first Android app using Kotlin. In my activity are a lot of UI elements which I use to show dynamic information (see example below). For performance reasons I learned:

"Define a variable in the class and initialize it in the onCreate()
method."

This is kind of messy and my question is: are there other techniques to fulfill the same task but have a cleaner code? The variables are used in other methods later.
class MainActivity : AppCompatActivity() {
    private lateinit var text_1: TextView
    private lateinit var text_2: TextView
    private lateinit var text_3: TextView
    private lateinit var text_4: TextView
    [...]

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        text_1 = findViewById(R.id.text1)
        text_2 = findViewById(R.id.text2)
        text_3 = findViewById(R.id.text3)
        text_4 = findViewById(R.id.text4)
        [...]
}

A:

From ViewBinding official docs:

View binding is a feature that allows you to more easily write code that interacts with views

First, enable ViewBinding in your module:
android {
    ...
    buildFeatures {
        viewBinding true
    }
}

Then, if you're calling views from activity, you should:
private lateinit var binding: ResultProfileBinding

override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    binding = ResultProfileBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}

and then you use binding instance to call the views:
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }

If you are calling views from a fragment, you should do it like following to avoid leaks:
private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}

