Kotlin Android Extensions deprecated. Что делать? Инструкция по миграции

от автора

Возможно, вы уже слышали, что Kotlin Android Extensions — плагин для Kotlin теперь deprecated.

kotlinx.android.synthetic is no longer a recommended practice. Removing in favour of explicit findViewById

Безусловно, это было очень удобно, особенно если у вас проект полностью на Kotlin. Однако, мир меняется и теперь нужно искать альтернативы. В этой статье мы кратко рассмотрим, что такое плагин Kotlin Android Extension, какие были проблемы с ним и что теперь нам, Android-разработчикам делать. Частично, использовался материал этой статьи. Итак, поехали.

Кратко о Kotlin Android Extensions

Kotlin Android Extensions — это плагин для Kotlin, позволяющий восстанавливать view из Activities, Fragments, и Views без написания стандартного бойлерплэйт-кода типа findViewById.
Плагин генерирует дополнительный код, который позволяет получить доступ к view в виде XML, так же, как если бы вы имели дело с properties с именем id, который вы использовали при определении структуры.

Также он создаёт локальный кэш view. При первом использовании свойства, плагин выполнит стандартный findViewById. В последующем, view будет восстановлен из кэша, поэтому доступ к нему будет быстрее.

Если это всё так удобно, то зачем его сделали deprecated?

Проблемы Kotlin Android Extensions

  • Используется глобальный нэйминг идентификаторов. Могут возникнуть ситуации, когда один и тот же идентификатор имеется у разных view в разных лэйаутах — соответственно только на этапе работы приложения вы узнаете о том, что использовали не тот id.
  • Возможно использовать только в проектах на Kotlin (кэп)
  • Отсутствует Null Safety. В случае, когда view представлена в одной конфигурации и отсутствует в другой — может возникнуть краш, т.к отсутствует обработка таких ситуаций
  • Невозможно использовать в многомодульных проектах. Очень распространённый сценарий: у вас есть модуль UI Kit, хранящий общие UI-компоненты, которые вы хотите переиспользовать в других модулях. До сих пор висит issues которое вряд ли поправят. В таком сценарии обычно используют старый добрый findViewById 🙁
  • Резюмируя приведённые недостатки, нетрудно понять, что этот подход не идеален — хотя, безусловно, очень удобен на небольших проектах. На больших проектах с многомодульной архитектурой и сотнями экранов — использование Kotlin Android Extensions уже не кажется идеальным решением.

Альтернативные способы

  • Использование KotterKnife (кек, даже не думайте).
  • Старый добрый FindViewById() — уже получше, но так себе.
  • Использование AndroidAnnotations (привет из 2015)
  • View Binding от Google — бинго!

View Binding от Google

Итак, победителем в этом списке выглядит ViewBinding от Google (не путайте с DataBinding). Давайте кратко рассмотрим, что это такое.

View Binding — это инструмент, который позволяет проще писать код для взаимодействия с view. При включении View Binding в определенном модуле он генерирует binding классы для каждого файла разметки (layout) в модуле. Объект сгенерированного binding класса содержит ссылки на все view из файла разметки, для которых указан android:id

Главные преимущества View Binding — это Null safety и Type safety.

Начало работы с View Binding

Начать работать с ViewBinding достаточно просто. Нужно добавить опцию в build.gradle:

android {     ...     buildFeatures {         viewBinding true     } }

После этого можно уже использовать. Каждый сгенерированный binding класс содержит ссылку на корневой view разметки (root) и ссылки на все view, которые имеют id. Имя генерируемого класса формируется как «название файла разметки», переведенное в camel case + «Binding». Например, для файла разметки result_profile.xml:

<LinearLayout ... >     <TextView android:id="@+id/name" />     <ImageView android:cropToPadding="true" />     <Button android:id="@+id/button"         android:background="@drawable/rounded_button" /> </LinearLayout> 

Будет сгенерирован класс ResultProfileBinding, содержащий 2 поля: TextView name и Button button.

Использование в Activity

Например у вас вот такой layout:

<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:context=".MainActivity">      <TextView         android:id="@+id/textView"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:text="Hello World!"         app:layout_constraintBottom_toBottomOf="parent"         app:layout_constraintLeft_toLeftOf="parent"         app:layout_constraintRight_toRightOf="parent"         app:layout_constraintTop_toTopOf="parent" />  </androidx.constraintlayout.widget.ConstraintLayout> 

Результат работы ViewBinding:

public final class ActivityMainBinding implements ViewBinding {   @NonNull   private final ConstraintLayout rootView;    @NonNull   public final TextView textView;

Использовать viewBinding можно так:

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

И теперь, после того, как получили ссылки на view:

binding.name.text = viewModel.name binding.button.setOnClickListener { viewModel.userClicked() }

Если вы используете ViewBinding во фрагменте и держите ссылку на binding во фрагменте (а не только в методе onCreateView()) то не забывайте очищать ссылки в методе onDestroyView().

Пример:

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 } 

Это необходимо делать из-за жизненного цикла фрагмента и view:
image

В целом, переключиться на ViewBinding достаточно не сложно, хотя и жаль, что Kotlin Android Extensions объявлен deprecated. Не забудьте присоединиться к нам в Telegram, а на платформе AndroidSchool.ru публикуются полезные материалы для Android-разработчика и современные туториалы.

Полезные ссылки:

ссылка на оригинал статьи https://habr.com/ru/post/526192/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *