ViewBinding против расширений Kotlin для Android с синтетическими представлениями

Чем новый ViewBinding соотносится с Kotlin Android Extensions с синтетическими привязками представлений?

Помимо NullSafety и TypeSafety, предоставляемых новыми ViewBindings, почему мы должны рассматривать отказ от Kotlin-способа использования синтетических привязок в Views?

Является ли новый ViewBinding более производительным, поскольку он заранее создает класс Binding?


person Rinav    schedule 12.10.2019    source источник
comment
Я создал несколько похожий вопрос на странице обсуждения.kotlinlang. Если у кого-то есть мысли по теме, смело отвечайте :)   -  person xinaiz    schedule 17.10.2019


Ответы (4)


Давайте рассмотрим эти два.


Конфигурация

Расширения Kotlin для Android

  1. Импортируйте соответствующие синтетические расширения макета: import kotlinx.android.synthetic.main.<layout>.*
  2. Ссылка на представления в коде через их идентификаторы: textView.text = "Hello, world!". Эти расширения работают с: Activities, Fragments и Views.

Просмотр привязки

  1. Создайте ссылку привязки внутри вашего класса: private lateinit var binding YourClassBinding
  2. Надуйте свой переплет binding = YourClassBinding.inflate(layoutInflater) внутри onCreate Activity и вызовите setContentView(binding.root), или накачайте его в Fragment onCreateView, а затем верните: return binding.root
  3. Ссылочные представления в коде через привязку с использованием их идентификаторов binding.textView.text = "Hello, world!"

Безопасность типов

Расширения Kotlin для Android и ViewBinding по определению являются типобезопасными, поскольку указанные представления уже приведены к соответствующим типам.


Нулевая безопасность

Расширения Kotlin для Android и ViewBinding являются нулевыми. ViewBinding здесь не имеет преимуществ. В случае KAE, если представление присутствует только в некоторых конфигурациях макета, IDE укажет вам на это:

введите описание изображения здесь

Таким образом, вы просто относитесь к нему как к любому другому типу, допускающему значение NULL, в Kotlin, и ошибка исчезнет:

введите описание изображения здесь


Применение изменений макета

В случае Kotlin Android Extensions изменения макета мгновенно переводятся в создание синтетических расширений, поэтому вы можете сразу же их использовать. В случае ViewBinding вам необходимо создать свой проект.


Неправильное использование макета

В случае Kotlin Android Extensions можно импортировать синтетические расширения неправильного макета, что приведет к NullPointerException. То же самое относится к ViewBinding, поскольку мы можем импортировать неправильный Binding класс. Тем не менее, более вероятно, что неправильный импорт будет пропущен из виду, чем неправильное имя класса, особенно если файл макета правильно назван после _17 _ / _ 18 _ / _ 19_, поэтому ViewBinding здесь имеет преимущество.


Резюме KAE и ViewBinding

  • Безопасность шрифта - Рисование.
  • Нулевая безопасность - Нарисуйте.
  • Шаблонный код - выигрывает KAE. Из документации по расширениям Kotlin для Android:

Плагин Kotlin Android Extensions позволяет нам получить тот же опыт, что и с некоторыми из этих библиотек, без необходимости добавлять какой-либо дополнительный код.

  • Применение изменений макета - выигрывает KAE. В отличие от ViewBinding, изменения происходят мгновенно.
  • Использование неправильного макета - ViewBinding побеждает

Я думаю, что существует большое заблуждение о том, что ViewBinding заменяет KAE. Люди слышат длинные ключевые слова и повторяют их, не проверяя их заранее. Конечно, ViewBinding - лучший вариант для разработки Java прямо сейчас (замена ButterKnife), но у Kotlin нет или мало преимуществ перед KAE ( см. раздел Использование неправильного макета).

Примечание: я уверен, что людям, использующим DataBinding, понравится ViewBinding :)

person xinaiz    schedule 19.10.2019
comment
Почему вы ничего не сказали об использовании переменных в DataBinding? Я думаю, что это важная функция - вообще отказаться от использования ссылок на представления. Кстати, вы можете использовать свою модель представления с помощью тегов <include ... />, что является еще одним большим преимуществом. - person Ircover; 21.10.2019
comment
@Ircover Речь шла о сравнении KAE и ViewBinding. DataBinding не является частью этого вопроса. - person xinaiz; 21.10.2019
comment
Упс, извините) Простое недоразумение. - person Ircover; 21.10.2019
comment
Позвольте мне указать, что синтетический импорт может привести к исключениям с нулевым указателем. Учитывая асинхронную задачу, которая не использует преимущества LiveData, вы можете получить нулевое представление, и компилятор ни в коем случае вас не предупредит. - person Camarero; 13.02.2020
comment
@EnricCamarero Разве это не то же самое с ViewBinding? Проблема в том, что представление больше не прикреплено, и ни одна из двух утилит с этим не справляется. - person xinaiz; 13.02.2020
comment
@xinaiz Я еще не пробовал привязку просмотра, так как синтетический импорт действительно помогает мне. Идентификатор, если привязка просмотра учитывает жизненный цикл, но, разумеется, расширения kotlin - нет (пока). - person Camarero; 13.02.2020
comment
Кстати, действительно хорошее объяснение! @xinaiz - person Camarero; 13.02.2020
comment
ViewBinding определенно имеет преимущество с точки зрения нулевой безопасности. Возьмем, к примеру, жизненный цикл фрагмента: вы можете ссылаться на представления в KAE в onCreateView перед созданием родительского макета. Это останется незамеченным во время компиляции, но вызовет NPE во время выполнения. С ViewBinding вы должны иметь ссылку на родительский макет, прежде чем ссылаться на его дочерние элементы. - person Ben Lewis; 24.02.2020
comment
@BenLewis, если ваша привязка определена как lateinit, у вас все еще есть та же проблема. Это означает, что без учета того, что вы используете KAE или ViewBinding, вы должны соблюдать некоторые строгие правила при написании кода во фрагменте. - person Flavio; 25.02.2020
comment
Применение изменений макета - при использовании ViewBinding вам не нужно создавать свой проект, после добавления нового представления с идентификатором вы можете мгновенно выполнить привязку. MyTextView ... - person Tayyab Mazhar; 01.03.2020
comment
Я думаю, что гораздо более вероятно, что вы неправильно ссылаетесь на одно синтетическое свойство, чем раздуваете совершенно неправильный макет привязки. Потому что в последнем случае представление больше не будет работать. Итак, я считаю, что View Binding имеет преимущество с точки зрения нулевой безопасности. - person Florian Walther; 18.07.2020

ViewBinding решил самую большую проблему kotlinx.android.synthetic. В synthetic привязке, если вы устанавливаете представление содержимого для макета, а затем вводите идентификатор, который существует только в другом макете, IDE позволяет вам выполнить автозаполнение и добавить новый оператор импорта. Если разработчик специально не проверит, что его операторы импорта импортируют только правильные представления, не существует безопасного способа убедиться, что это не вызовет проблемы во время выполнения. Но в ViewBinding вы должны использовать свой layout объект привязки для доступа к его представлениям, чтобы вы никогда не вызывали представление в другом макете, и если вы захотите сделать это, вы получите ошибку компиляции, а не ошибку времени выполнения. Вот пример.

Мы создаем два макета, называемых activity_main и activity_other, вот так:

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <TextView
        android:id="@+id/message_main"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</RelativeLayout>

activity_other.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                >

    <TextView
        android:id="@+id/message_other"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</RelativeLayout>

Теперь, если вы напишете свою деятельность так:

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_other.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //Application will crash because "message_other" doesn't exist in "activity_main"
        message_other.text = "Hello!"
    }
}

ваш код будет компилироваться без ошибок, но ваше приложение выйдет из строя во время выполнения. Поскольку представление с message_other id не существует в activity_main, и компилятор не проверял это. Но если вы используете ViewBinding так:

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        //This code will never compile and the IDE shows you an error
        binding.message_other.text = "Hello!"
    }
}

ваш код никогда не будет компилироваться, и Android Studio показывает вам ошибку в последней строке.

person Squti    schedule 23.10.2019
comment
Вы также можете использовать LayoutInflater для расширения View, а затем ссылаться на его определенные поля через переменную. - person NapoleonTheCake; 16.01.2020
comment
В реальной жизни это кажется очень маловероятным. - person Bencri; 17.02.2020
comment
Пример не имеет смысла. Вы использовали это неправильно. Зачем вам импортировать неправильную вещь (activity_other)? Каждая неверно используемая вами структура может вызвать проблемы. - person android developer; 02.04.2020
comment
@Bencri Это может произойти из-за разных конфигураций макета. - person Noam; 12.07.2020
comment
как сказал @Bencri, это очень маловероятно, особенно если у вас есть свои собственные соглашения об именах для макетов, называя эти представления в соответствии с экраном, которому они принадлежат. Например, вы можете переименовать message_main и message_other в main_message и other_message, чтобы избежать двусмысленности. - person Dimas Mendes; 25.07.2020
comment
Обратите внимание, что вы уже должны присваивать своим идентификаторам уникальные имена для каждого макета, например. main_myText против other_myText, чтобы избежать чрезмерных ошибок рефакторинга (и общей простоты разделения контекстов). - person Tom; 04.08.2020

kotlinx.android.synthetic больше не является рекомендуемой практикой, говорится в сообщении Google в одном сообщении о фиксации "в одной из веток Reddit

https://android-review.googlesource.com/c/platform/frameworks/support/+/882241 "

Synthetics не разрабатывается Google, это часть расширения kotlin для Android, созданного JetBrains, и постепенно разработчики Google для Android начали заменять Synthetics на ViewBindins в своих демонстрациях и исходных кодах.

«Теперь возникает вопрос, какой из них мы должны принять во внимание».

Согласно Google (View binding, ButterKnife, Kotlin Synthetics) эти библиотеки успешно используются многими приложениями и решают ту же проблему.

Но для большинства приложений Google рекомендует попробовать привязку представлений вместо этих библиотек. Поскольку привязка представлений обеспечивает более безопасный и точный поиск представлений.

Прикрепленное эталонное изображение, чтобы быстро прояснить ситуацию. введите описание изображения здесь

Однако, если вы хотите пойти в отдел, вы можете перейти по указанной ниже ссылке. https://medium.com/androiddevelopers/use-view-binding-to-replace-findviewbyid-c83942471fc

person SourabhTech    schedule 10.03.2020
comment
1. Всегда нулевое значение - привязка представления все равно будет аварийно завершена, если используется до инфляции или после завершения жизненного цикла представления - ничем не отличается от синтетики - для ViewBinding должен быть КРАСНЫМ цветом. 2. Ссылочные идентификаторы только из текущего макета - это правда, но IDE указывает, из какого макета вы хотите импортировать данный идентификатор, так что это не большая проблема. 3. Поддерживает Kotlin и Java - плохой аргумент, если вы можете использовать Kotlin в разработке для Android, тогда зачем использовать Java. 4. Количество необходимого кода - синтетика Kotlin имеет наименьшее количество, должно быть очень низким в таблице. - person xinaiz; 11.03.2020
comment
@xinaiz Почему вы используете его перед накачиванием, следуйте правильному способу использования, иначе вы наверняка столкнетесь с проблемами. Вы прошли по ссылке перед тем, как проголосовать против и опубликовать комментарий medium. ru / androiddevelopers / - person SourabhTech; 11.03.2020
comment
Да, я читал это некоторое время назад. Перед накачиванием не пользуюсь, просто говорю, что это возможно. Правильный путь подразумевает риски, не так ли? Кроме того, вы пропустили or after view lifecycle ends часть? - person xinaiz; 11.03.2020
comment
@xinaiz 2. Но есть шанс использовать неправильный идентификатор, если проект больше, а также для того же имени ресурса, если над проектом работают несколько разработчиков. 3.Да, может быть требование к проекту, в котором вы должны использовать как java, так и kotlin (если проект уже разработан на java и начал интригацию с kotlin, тогда определенно это помогает) 4. Для Synthetics вам нужно импортировать отдельную библиотеку, но для привязки просмотра он уже есть в Gradle, поэтому, очевидно, потребовалось меньше кода. - person SourabhTech; 11.03.2020
comment
@xinaiz Итак, вы собираетесь использовать идентификатор представления после завершения жизненного цикла представления? Как вы думаете, id должен быть там, и мы должны следовать этой практике, чтобы сознательно создавать проблемы. - person SourabhTech; 11.03.2020
comment
Разработка под Android является асинхронной, поэтому фоновую задачу легко завершить, когда просмотр больше не доступен, например. ваш код пытается получить доступ к представлениям в обратном вызове и стреле, NPE. Конечно, исправлено LiveData, но безопасность не связана с ViewBinding :) - person xinaiz; 11.03.2020
comment
В ответ на 4. Какая библиотека? По умолчанию он включен. Это спор о apply plugin: 'kotlin-android-extensions' против viewBinding { enabled = true }. Нет особой разницы. - person xinaiz; 11.03.2020
comment
@xinaiz Я думаю, вам нужно просмотреть документацию, чтобы получить более четкое представление. developer.android.com/topic/libraries/view-binding Для информации вы должны обнулить объект привязки при вызове onDestoryView (), это предотвратит сбой формы во время обратного вызова, если. И джентльмен, вы должны придерживаться одного утверждения, в первом комментарии, на который вы ответили, синтетика имеет самый низкий код, а в недавнем комментарии говорится, что нет большой разницы в обоих (что уже упоминалось на изображении). - person SourabhTech; 11.03.2020

Расширения Kotlin для Android будут устаревшими с Kotlin 1.4.20, поэтому я бы рекомендовал использовать ViewBinding.

https://proandroiddev.com/migrating-the-deprecated-kotlin-android-extensions-compiler-plugin-to-viewbinding-d234c691dec7

person Henning    schedule 05.11.2020
comment
Это наиболее разумная причина, по которой мы должны использовать viewBinding. ржу не могу - person J.Dragon; 27.11.2020
comment
С тех пор, как я написал этот ответ, я начал рефакторинг своего кода. Есть вещи, которые были проще с синтетикой, но также более подвержены ошибкам. Обнаружил несколько ошибок макета, которые я сделал с синтетикой, которые невозможно исправить с помощью ViewBinding. Так что это компромисс между скоростью и краткостью в пользу стабильности, я думаю, что это шаг в правильном направлении. - person Henning; 28.11.2020