The Other Common “Gimme the Views” Options
We have seen both data binding and view binding as ways of interacting with the widgets in our layout resources.
Believe it or not… there are others, though in general they are no longer recommended.
findViewById()
The original solution, dating back to Android 1.0, is a method called findViewById()
. This method is available on Activity
, View
, and ViewGroup
. You pass in a widget resource ID (R.id.whatever
) and it returns the first View
that it finds that matches that ID… or null
if it fails to find something:
val button = findViewById<Button>(R.id.whatever)
The problem is that there is no validation on the widget ID that you supply. So, while we like to pretend that findViewById()
will always return our desired widget, that is based on some assumptions:
- The widget ID is valid for this context — for example, you did not provide a widget ID from Layout A to a
findViewById()
call that is tied to something that instead inflated Layout B - The layout is already inflated by this point — a mistake many early Android developers made was to call
findViewById()
beforesetContentView()
, for example
The compiler will let you call findViewById()
on any View
or ViewGroup
passing in any R.id
resource… even if there is no possible way that a widget with that ID will be found. Most of the time, you will know what widget IDs to use in what circumstances and will create valid findViewById()
calls. Sometimes, though, you will make mistakes… and then it comes down to testing as to whether or not you catch those mistakes before they start affecting users. View binding helps to eliminate that risk.
As a result, findViewById()
is available but is no longer recommended for most developers. What view binding and data binding do is give us code-generated classes that limit our findViewById()
usage to cases that are far more likely to succeed.
Kotlin Synthetic Accessors
Kotlin synthetic accessors come “for free” simply by adding the kotlin-android-extensions
plugin to a module.
The effect is that we can add an import statement that references our layout resource (import kotlinx.android.synthetic.main.activity_main.*
, referencing the activity_main
resource). With that, we get properties for each of the named widgets in the layout. Under the covers, generated code will perform the findViewById()
call for us.
The larger the project, though, the greater the risk is that you will use the wrong imports. Once you start getting dozens or hundreds of layout resources, making sure that you use the right imports starts to become a challenge. The compiler will be very happy to let you use any import you want. However, if you try referencing a widget from Layout X and you are really using Layout Y, it is likely that you will wind up crashing with a NullPointerException
somewhere along the line.
Also, this approach is only available for Kotlin code — it adds no value to a Java project.
Most importantly, though, this plugin is deprecated by JetBrains as of Kotlin 1.4.20. So, while Kotlin synthetic accessors were “the go-to” Kotlin solution as recently as 2018, they are no longer recommended, even by their developers.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.