Каждый, кто начинает писать под Android, быстро знакомится с findViewById. Код с ним работает, но выглядит громоздко, а при ошибке в названии id приложение падает. Сегодня на занятии в Android Studio мы освоим более удобный инструмент — ViewBinding. Он автоматически создаёт ссылки на все элементы разметки, и вы обращаетесь к ним через одну переменную, не боясь опечаток. Урок построен на языке Kotlin и рассчитан на тех, кто уже пробовал что-то создавать, но хочет писать чище и безопаснее.
Чем ViewBinding лучше findViewById
При использовании findViewById вы вручную ищете каждый элемент по id и приводите его к нужному типу. Если ошибиться в id, компилятор не заметит, и ошибка проявится только при запуске. ViewBinding же генерирует для каждого XML-файла отдельный класс, в котором уже есть все View с правильными типами. Обращение к binding.myButton даёт сразу Button, а не View, и никаких приведений не требуется. Плюс null-безопасность и проверка на этапе компиляции делают код надёжным.
Как включить ViewBinding в проекте
Никакие библиотеки добавлять не нужно — ViewBinding встроен в Android Gradle Plugin. Откройте build.gradle.kts уровня модуля app и внутри блока android добавьте пару строк. После синхронизации Gradle генерация классов включится для всех XML-файлов разметки.
android {
// ... compileSdk и прочее
buildFeatures {
viewBinding = true
}
}
Если для какого-то конкретного макета ViewBinding не нужен (например, он редко обновляется), можно отключить его прямо в XML-файле, добавив атрибут tools:viewBindingIgnore="true" в корневой элемент.
Переписываем Activity на ViewBinding
Допустим, у нас есть простой экран с текстовой меткой и кнопкой, как в самом первом занятии. Раньше мы находили их через findViewById. Теперь вместо этого в onCreate нужно объявить переменную binding и использовать её.
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.myText.text = "Привет, ViewBinding!"
binding.myButton.setOnClickListener {
binding.myText.text = "Кнопка нажата"
}
}
}
Класс ActivityMainBinding сгенерирован автоматически из имени файла activity_main.xml путём преобразования к UpperCamelCase и добавления суффикса Binding. Все id из разметки превратились в поля этого класса.
ViewBinding во Fragment
Для фрагментов подход немного отличается, потому что нужно вовремя очищать ссылку, чтобы избежать утечек памяти. Создадим фрагмент с тем же макетом и правильно настроим binding.
class MyFragment : Fragment() {
private var _binding: FragmentMyBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentMyBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.myText.text = "Фрагмент с ViewBinding"
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Переменная _binding обнуляется в onDestroyView — это важно, потому что View фрагмента может быть уничтожен раньше самого фрагмента, а ссылка на него будет держать память. Код аккуратный и безопасный.
ViewBinding в адаптере RecyclerView
Адаптер тоже можно переписать на ViewBinding, чтобы не вызывать findViewById в ViewHolder. Вместо этого ViewHolder принимает объект binding, и доступ к элементам идёт напрямую.
class FruitAdapter(
private val fruitList: List<Fruit>,
private val onItemClick: (Fruit) -> Unit
) : RecyclerView.Adapter<FruitAdapter.FruitViewHolder>() {
class FruitViewHolder(val binding: ItemFruitBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder {
val binding = ItemFruitBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return FruitViewHolder(binding)
}
override fun onBindViewHolder(holder: FruitViewHolder, position: Int) {
val fruit = fruitList[position]
holder.binding.tvName.text = fruit.name
holder.binding.tvDescription.text = fruit.description
holder.binding.root.setOnClickListener { onItemClick(fruit) }
}
override fun getItemCount(): Int = fruitList.size
}
Советы для начинающих
- Всегда обнуляйте _binding во Fragment. Это предотвращает утечки памяти и является рекомендацией Google.
- Используйте lateinit в Activity. Переменная binding инициализируется в onCreate и живёт до уничтожения Activity, поэтому lateinit здесь полностью оправдан.
- Не забывайте, что binding.root — это корневой View. Именно его нужно передавать в setContentView или возвращать из onCreateView.
Что мы освоили
Этот урок в Android Studio на языке Kotlin показал, как отказаться от findViewById и писать более чистый код с помощью ViewBinding. Вы включили генерацию классов, переписали Activity и Fragment, а также адаптер RecyclerView. Теперь обращение к кнопкам и тексту стало лаконичным и безопасным. Попробуйте прямо сейчас перевести свой проект на ViewBinding — вы увидите, насколько меньше стало кода и как легко его читать.