Kotlinx android synthetic main

Kotlin Android Extensions: полное руководство

Oct 9, 2018 · 7 min read

Если у вас уже есть опыт разработки приложений для Android, вероятно, вы уже устали использовать findViewById, чтобы восстанавливать view. Или, может быть, вы уже сдались и начали использовать известную библиотеку ― Butterknife. Если это ваш случай, то вы влюбитесь в Kotlin Android Extensions.

Что такое Kotlin Android Extensions?

Kotlin Android Extensions — это плагин для Kotlin, который включён в стандартный пакет. Он позволяет восстанавливать view из Activities, Fragments, и Views удивительно-бесшовным способом.

Плагин генерирует дополнительный код, который позволяет получить доступ к view в виде XML, так же, как если бы вы имели дело с properties с именем id, который вы использовали при определении структуры.

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

Как этим пользоваться

Посмотрим, насколько это просто. В первом примере рассмотрим activity:

Включаем Kotlin Android Extensions в наш код

Хотя плагин уже интегрирован (устанавливать новый не нужно), если вы хотите его использовать, вам нужно подключить плагин в модуль Android:

И это все что вам потребуется. Теперь вы можете начать работу с ним.

Восстанавливаем view из XML

С этого момента, восстановить view, также просто, как использовать view id, которое вы определили в XML, непосредственно в вашем activity.

Представьте, что у вас есть такой XML:

Как видно, в TextView есть id welcomeMessage .

Просто напишите следующий код в MainActivity:

Чтобы это работало, нужен специальный импорт (я написал его ниже), но IDE может автоматически импортировать его. Проще и быть не может!

Как я уже упоминал, сгенерированный код включает кэш view, поэтому, если вы повторно обратитесь к view, это не потребует выполнения findViewById снова.

Давайте посмотрим, что происходит под капотом.

Магия Kotlin Android Extensions

Когда начинаешь работать с Kotlin, действительно интересно понять байт-код, который генерируется при использовании той или иной функции. Это поможет вам понять скрытую цену ваших решений.

В меню Tools → Kotlin, вы найдёте мощный инструмент Show Kotlin Bytecode. Если кликнуть по нему, вы увидите байт-код, который будет сгенерирован, когда открытый файл класса будет скомпилирован.

Для большинства людей, байт-код не особенно полезен, но тут есть ещё одна опция: Decompile.

Эта опция покажет вам Java репрезентацию байт-кода, который был сгенерирован в Kotlin. Так, вы сможете более-менее понять, как будет выглядеть код Java, эквивалентный тому, что вы написали на Kotlin.

Я собираюсь использовать это на примере activity и посмотреть код, сгенерированный Kotlin Android Extensions.

Вот интересная часть:

Это и есть кэш view, о котором мы говорили.

При запросе view, его поиск начинается в кэше. Если view нет в кэше, то он туда будет добавлен, как только будет найден. Всё просто.

Кроме того, в код добавляется функция для очистки кэша: clearFindViewByIdCache. Её можно использовать, скажем, когда старые view уже не актуальны и вам нужно получить новые.

Тогда, эта строка:

Превращается в эту:

Таким образом, плагин не генерирует свойства для каждого view, это ненастоящие свойства. Плагин просто заменяет код во время компиляции, чтобы получить доступ к кэшу view. Затем, он приводит к нужному типу и вызывает метод.

Kotlin Android Extensions ― работа с фрагментами

Этот плагин можно использовать с фрагментами.

Проблема с фрагментами заключается в том, что view может обновится, а экземпляр фрагмента останется прежним. Что произойдёт? А то, что view находящееся в кэше, перестанет быть валидным.

Давайте посмотрим код, который генерирует плагин, если мы используем его с фрагментом. Я создаю простой фрагмент, который использует тот же XML, который я написал выше:

В onViewCreated , я снова изменяю текст TextView . Что насчёт сгенерированного байт-кода?

Всё тоже самое, как и в activity, с небольшой разницей:

Читайте также:  Как создать свои часы для android

Когда view перестанет быть актуальным, этот метод вызовет clearFindViewByIdCache , так что мы в безопасности!

Kotlin Android extensions и Custom View

С custom view, плагин работает схожим образом. Скажем, у нас есть такой view:

Я создаю очень простое custom view и генерирую конструкторы с новым намерением, которое использует аннотацию @JvmOverloads :

В примере выше, я изменяю текст в itemTitle . Сгенерированный код должен искать view в кэше. Не имеет смысла снова копировать тот же код полностью. Вы можете наблюдать это в строке, которая изменяет текст:

Отлично! В custom views мы тоже вызываем findViewById только первый раз.

Восстанавливаем views из другого view

Последняя альтернатива, которую предлагает Kotlin Android Extensions: использовать свойства напрямую из другого view.

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

Вы также можете получить доступ к subviews напрямую, просто используя этот плагин:

Хотя плагин и может помочь заполнить import, здесь есть небольшое отличие:

Несколько вещей, которые вам нужно знать:

  • Во время компиляции, вы можете ссылаться на любое view из любого другого view. Это значит, вы можете ссылаться на view, которое не является его прямым потомком. Это плохо скажется на времени выполнения при попытке восстановить view, которого не существует.
  • В этом случае, view не кэшировано, как в случае с Activities и Fragments.

Почему так? В отличие от предыдущих случаев, здесь у плагина нет места, чтобы генерировать необходимый код для кэша.

Если вы снова перечитаете код, который сгенерирован плагином, где вызываются свойства из view, вы увидите это:

Как видно, здесь нет запроса к кэшу. Будьте осторожны, если у вас комплексное view, и вы используете его в адаптере. Это может повлиять на производительность.

Также у вас есть альтернатива: Kotlin 1.1.4

Kotlin Android Extensions версии 1.1.4

Начиная с этой, новой версии Kotlin, в Android Extensions включили новые интересные функции: кэш в любом классе (включая ViewHolder ) и новая аннотация, названная @Parcelize . Также есть способ настраивать сгенерированный кэш.

Мы вернёмся к ним через минуту, но вам следует знать, что эти новые фичи ― не завершены, так что, вам нужно включить их с помощью build.gradle :

Применяем на ViewHolder (или любом пользовательском классе)

Теперь есть простой способ построить кэш для любого класса. Единственное требование заключается в том, чтобы класс имплементировал интерфейс LayoutContainer . Этот интерфейс предоставит view, которое плагин будет использовать, чтобы искать subviews. Представьте, что у вас есть ViewHolder, который содержит view со структурой, описанной в предыдущем примере. Всё что вам нужно сделать:

containerView ― единственное, что мы перезаписываем из интерфейса LayoutContainer . Это все что вам необходимо.

С этого момента, у вас есть доступ к views напрямую. Нет необходимости присоединять itemView, чтобы получить доступ к subviews.

Ещё раз, если вы посмотрите на сгенерированный код, вы увидите, что view берётся из кэша:

Здесь я применял его на ViewHolder , но это достаточно универсальный подход и его можно использовать с любым классом.

Kotlin Android Extension. Реализация Parcelable

С новой аннотацией @Parcelize , можно с лёгкостью имплементировать Parcelable c любым классом.

Вам нужно добавить аннотацию, а плагин сделает за вас всю сложную работу:

Далее, как вам должно быть известно, можно добавить объект к любому намерению:

И восстановить объект из намерения в любой точке (в этом случае: из activity):

Настройка кэша

В этот экспериментальный набор, включена новая фича ― аннотация @ContainerOptions . Она даёт возможность настраивать способ построения кэша, или даже предотвращать его создание классом.

По умолчанию, используется Hashmap , как мы видели ранее. Его можно заменить на SparseArray из Android framework, что может быть более эффективно в некоторых ситуациях. Или, если вам не нужен кэш для класса, по каким-то причинам, такая возможность тоже есть.

Вот как это использовать:

На данный момент существуют следующие варианты:

Заключение

Вы увидели, как легко работать с Android views в Kotlin. Благодаря простому плагину, можно забыть обо всём этом ужасном коде, связанном с восстановлением view. Этот плагин создаёт для нас необходимые свойства с приведением правильного типа, безо всяких проблем.

Кроме того, Kotlin 1.1.4 добавляет интересные фичи, которые будут действительно полезны в некоторых случаях, к которым плагин ранее не имел отношения.

Источник

Kotlin Android Extensions: Say goodbye to findViewById (KAD 04)

Warning! Kotlin Android Extensions are deprecated, you should start using View Binding.

If you’ve been developing Android Apps for some time, you’re probably already tired of working with findViewById in your day-to-day life to recover views. Or maybe you gave up and started using the famous Butterknife library. If that’s your case, then you’ll love Kotlin Android Extensions.

Kotlin Android Extensions: What’s this?

Kotlin Android Extensions are another Kotlin plugin that is included in the regular one, and that will allow recovering views from Activities, Fragments, and Views in an amazing seamless way.

Читайте также:  Смартфон с чистым андроидом до 20000

The plugin will generate some extra code that will allow you to access views in the layout XML, just as if they were properties with the name of the id you used in the layout definition.

It also builds a local view cache. So the first time a property is used, it will do a regular findViewById. But next times, the view will be recovered from the cache, so the access will be faster.

How to use them

Let’s see how easy it is. I’ll do this first example with an activity:

Integrating Kotlin Android Extensions in our code

Though the plugin comes integrated into the regular one (you don’t need to install a new one), if you want to use it you have to add an extra apply in the Android module:

And that’s all you need. You’re now ready to start working with it.

Want to learn Kotlin?

Check my free guide to create your first project in 15 minutes!

Recovering views from the XML

From this moment, recovering a view is as easy as using the view id you defined in the XML directly into your activity.

Imagine you have an XML like this one:

As you can see, the TextView has welcomeMessage id.

Just go to your MainActivity and write it:

To be able to use it, you need a special import (the one I write below), but the IDE is able to auto-import it. Couldn’t be easier!

As I mentioned above, the generated code will include a view cache, so if you ask the view again this won’t require another findViewById

Let’s see what’s behind the scenes.

The magic behind Kotlin Android Extensions

When you start working with Kotlin, it’s really interesting to understand the bytecode that is being generated when you use one feature or another. This will help you understand the hidden costs behind your decisions.

There’s a powerful action below Tools –> Kotlin, called Show Kotlin Bytecode. If you click here, you’ll see the bytecode that will be generated when the class file you have opened is compiled.

The bytecode is not really helpful for most humans, but there’s another option here: Decompile.

This will show a Java representation of the bytecode that is generated by Kotlin. So you can understand more or less the Java equivalent code to the Kotlin code you wrote.

I’m going to use this on my activity, and see the code generated by the Kotlin Android Extensions.

The interesting part is this one:

Here it is the view cache we were talking about.

When asked for a view, it will try to find it in the cache. If it’s not there, it will find it and add it to the cache. Pretty simple indeed.

Besides, it adds a function to clear the cache: clearFindViewByIdCache . You can use it for instance if you have to rebuild the view, as the old views won’t be valid anymore.

is converted into this:

So the properties are not real, the plugin is not generating a property per view. It will just replace the code during compilation to access the view cache, cast it to the proper type and call the method.

Kotlin Android Extensions on fragments

This plugin can also be used on fragments.

The problem with fragments is that the view can be recreated but the fragment instance will be kept alive. What happens then? This means that the views inside the cache would be no longer valid.

Let’s see the code it generates if we move it to a fragment. I’m creating this simple fragment, that uses the same XML I wrote above:

In onViewCreated , I again change the text of the TextView . What about the generated bytecode?

Everything is the same as in the activity, with this slight difference:

When the view is destroyed, this method will call clearFindViewByIdCache , so we are safe!

Kotlin Android extensions on a Custom View

It will work very similarly on a custom view. Let’s say we have a view like this:

I’m creating a very simple custom view and generate the constructors with the new intent that uses @JvmOverloads annotation:

In the example above, I’m changing the text to itemTitle . The generated code should be trying to find the view from the cache. It doesn’t make sense to copy all the same code again, but you can see this in the line that changes the text:

Читайте также:  Топ планировщик задач для андроид

Great! We are only calling findViewById the first time in custom views too.

Recovering views from another view

The last alternative Kotlin Android Extensions provide is to use the properties directly from another view.

I’m using a layout very similar to the one in the previous section. Imagine that this is being inflated in an adapter for instance.

You can also access the subviews directly, just using this plugin:

Though the plugin will also help you fill the import, this one is a little different:

There are a couple of things you need to know about this:

  • In compilation time, you’ll be able to reference any view from any other view. This means you could be referencing to a view that is not a direct child of that one. But this will fail in execution time when it tries to recover a view that doesn’t exist.
  • In this case, the views are not cached as it did for Activities and Fragments.

Why is this? As opposed to the previous cases, here the plugin doesn’t have a place to generate the required code for the cache.

If you again review the code that is generated by the plugin when calling a property from a view, you’ll see this:

As you can see, there’s no call to a cache. Be careful if your view is complex and you are using this in an Adapter. It might impact the performance.

Or you have another alternative: Kotlin 1.1.4

Kotlin Android Extensions in 1.1.4

Since this new version of Kotlin, the Android Extensions have incorporated some new interesting features: caches in any class (which interestingly includes ViewHolder ), and a new annotation called @Parcelize . There’s also a way to customize the generated cache.

We’ll see them in a minute, but you need to know that these features are not final, so you need to enable them adding this to you build.gradle :

Using it on a ViewHolder (or any custom class)

You can now build a cache on any class in a simple way. The only required thing is that your class implements the interface LayoutContainer . This interface will provide the view that the plugin will use to find the subviews. Imagine we have a ViewHolder that is holding a view with the layout described in the previous examples. You just need to do:

The containerView is the one that we are overriding from the LayoutContainer interface. But that’s all you need.

From that moment, you can access the views directly, no need of prepending itemView to get access to the subviews.

Again, if you check the code generation, you’ll see that it’s taking the view from the cache:

I’ve used it here on a ViewHolder , but you can see this is generic enough to be used in any class.

Kotlin Android Extension to implement Parcelable

With the new @Parcelize annotation, you can make any class implement Parcelable in a very simple way.

You just need to add the annotation, and the plugin will do all the hard work:

Then, as you may know, you can add the object to any intent:

And recover the object from the intent at any point (in this case in the target activity):

Customize the cache build

A new feature included in this experimental set is a new annotation called @ContainerOptions . This one will allow you to customize the way the cache is built, or even prevent a class from creating it.

By default, it will use a Hashmap , as we saw before. But this can be changed to use a SparseArray from the Android framework, which may be more efficient in certain situations. Or, if for some reason, you don’t want a cache for a class, you also have that option.

This is how it’s used:

Currently, the existing options are these:

Conclusion

You’ve seen how easy is to deal with Android views in Kotlin. With a simple plugin, we can forget about all that awful code related to view recovery after inflation. This plugin will create the required properties for us casted to the right type without any issues.

Besides, Kotlin 1.1.4 has added some interesting features that will be really helpful in some cases that were not previously covered by the plugin.

If you like what you’ve seen, I encourage you to sign up for my free training, where I’ll tell you everything you need to learn about how to create your own Android Apps in Kotlin from scratch.

Источник

Оцените статью