Плагин для Android Studio/Intelij IDEA с помощью которого можно мигрировать кодовую базу с котлиновской синтетики на view-binding. Поддерживает Android Studio 4.1+ и Intelij IDEA 2020.1+
- Скачать jar из последнего релиза
- Preferences -> Plugins -> Settings -> Install Plugin From Disk
- Выбрать jar
- Перезагрузить студию
- Точка входа в плагин появится в верхнем меню
В первом табе происходит настройка миграции, указание сущности которая будет мигрировать, то как будет инициализироваться view binding, где будет инициализироваться, указание доп импортов и т.д.
Чекбокс "Локальная переменная" - если он установлен, то binding переменная будет создана в методе указанном в поле "Метод инициализации", так что после того как чекбокс становиться активным поле "Метод инициализиации" становиться обязательным
Поле "Родительский класс" - это обязательное поле, которое заполняется именем родительского класса сущности которую нужно перевести на view binding. Например нам нужно перевести все сущности которые наследуются от Fragment, значит пишем там Fragment.
Поле "Название базового класса" - поле в которе вводится название базового класса сущности. Например нужно перевести все фрагменты на view binding, и есть базовый абстрактный класс BaseFragment, в котором переменная binding установленная абстрактной, следовательно нужно в каждом наследнике BaseFragment переопределять эту переменную. Значит указываем в Поле "Родительский класс" Fragment, в этом поле BaseFragment. И плагин везде где родитель BaseFragment - переопределит binding переменную(добавит override), а где только Fragment - создаст новую.
Поле "Название binding переменной" - то как будет называться генерируемая переменная. По умолчания binding
Поле "Метод инициализации" - поле которое нужно заполнить если необходимо инициализировать view binding переменную в каком то методе. Она используется как в связке с Чекбоксом "Локальная переменная", так и без него.
- Если выбран чекбокс и заполнено это поле, то переменная будет создана исключительно в в том методе, который указан в поле
- Чекбокс не выбран и заполнено поле, будет создана глобальная переменная с lateinit и инициализирована в методе который указан в этом поле
Поле "Шаблон инициализации" - поле в котором прописывается то как будет инициализирована переменная. Т.к. инициализация сопрежена с обращения к, сгенерированным view binding плагином, классами, то в этом поле можно указать , где это сгенерированный view binding класс, для обрабатываемого класса. Например есть делегат, с помощью которого нужно инициализировать во всех фрагментах binding. Для Фрагмента с лэйаутом R.layout.fragment_search эта инициализация должно выглядеть так val binding by fragmentBindingDelegate(FragmentSearchViewBinding::bind). Значит нужно вписать в это поле by fragmentBindingDelegate(::bind). И тогда в каждом фрагменте, где плагин сможет найти лэйаут будет подставлен класс сгенеренный на основе этого лэйаута.
Поле "Необходимы импорты" - плагин по умолчанию удаляет все импорты с синтетикой и добавляет импорты с view binding. На иногда необходимы еще некоторые импорты, например когда используешь тот же делегат для инициализации. Например: ru.rabota.app2.delegate.viewbinding и тогда в списке импортов у каждого обработанного файла появится import ru.rabota.app2.delegate.viewbinding. Это поле так же имеет правило: один импорт - одна строка
Кнопка "Мигрировать" - запускает процесс генерации переменной и замены импортов. После нажатия все повиснет и это нормально. После выполнения миграции появится диалог о завершении
Кнопка "Сбросить" - сбрасывает все настройки и очищает поля в этом табе
Кнопка "Отмена" - закрывает диалог
Второй таб позволяет заменять родительские классы. Это необходимо если во время переезда на view-binding в родительском классе добавился новый generic и чтобы во всех наследуемых классах руками его не добавлять может пригодится эта фича.
Поле "Что заменяем" - в этом поле указывается класс от которого наследуются и который изменился/заменился. Например у был класс BaseFragment и стал BaseFragment<ViewBinding, ViewModel> и везде нужно подставить этот ViewBinding. Значит в этом поле указывается имя такого класса который необходимо заменить т.е. BaseFragment
Поле "На что заменяем" - в этом поле указывается выражение на которое заменяется класс указанный выше. Это поле имеет 2 особенности:
- Когда заменяем BaseFragment на BaseFragment<ViewBinding, ViewModel>, нужно добавить view binding класс и сохранить имеющуюся уже там viewmodel класс. И тут нам на помощь приходит & , где type аналогичен type из шаблона инициализации, а , где index это индекс generic'а, начиная с 0. В этом примере в поле будет записано BaseFragment<, <0>>. Где <0> - это ViewModel
- Так же много где есть аргументы в первичном конструкторе, для того что бы они не исчезли при замене указывается [index] - где index это индекс аргумента, начиная с 0. Например есть BaseItem(abs, test), заменить на SuperItemBase(abs, test). Значит в этом поле нужно указать SuperItemBase<>([0],[1])
Поле "Необходимый импорт" - импорт который добавляется в процессе замены в каждый обработанный файл. Например: ru.rabota.app2.delegate.viewbinding и тогда в списке импортов у каждого обработанного файла появится import ru.rabota.app2.delegate.viewbinding
Кнопка "Заменить" - запускает процесс замены
Кнопка "Очистить" - очищает поля
Здесь во всех фрагментах сгенерится переменная с именем binding, а в тех кто наследовался от BaseFragment переменная биндинг будет override. Инициализация будет такая binding by someDelegate(NameViewBinding::bind). И в каждый обработанный файл добавиться импорт ru.rabota.app2.delegate.someDelegate. И у всех вьюшек в каждом классе вначале появится binding. На данном скриншоте приведен пример миграции итема списка. Т.е. во всех классах с родителем Item, в методе onBind будет сгенерирована переменная с названием itemBinding и инициализирована так: itemBinding = NameViewBinding.bind(viewHolder.itemView) В этом примере во все наследования от BaseFragment будет добавлен generic c типом биндинга который был найден в классе. Например: было MainFragment: BaseFragment() станет MainFragment: BaseFragment() И так же во всех классах которые наследуются от BaseFragment, первый дженерик сохранится за счет того что было прописано <0>, и добавится новый с типом биндинга за счет добавления В этом примере происходит замена наследования с добавлением нового аргумента и сохранением старого. Например: было MainItem(orientation: Int, data: Int): BaseItem(orientation) станет MainItem(orientation: Int, data: Int): BaseItem(orientation, data) И так же во всех классах которые наследуются от BaseItem, первый аргумент сохранится за счет того что было прописано [0], и добавится новый за счет добавления data