Pull to refresh
4K+
1
Олег@first_row

Android&IOS разработчик

2
Subscribers
Habr Career
Send message

Подытоживая, о вашем методе: общий вызывающий код, с единым jmethodid, НО прослойка с необходимостью поиска, switch case, наследования всех листенеров от единого и приведение к наследникам в коде вызова. Плюсом возвращаемое значение Object, необходимость доп манипуляций для получения простого типа. Параметры, кстати, тоже Object, что требует конвертации всякий раз даже если передаются простые типы.

О моем методе: вызывающий код и инициализация отдельная для каждого листенера, что можно назвать недостатком, но зато имеем непосредственный вызов методов листенера, никаких прослоек, не нужно наследоваться от общего класса листенера в java, логика полностью повторяет привычную и легко переносится на другие системы, никаких лишних преобразований типов.

Насчет переписывания: в ios у меня схожая реализация оберток, только проще, без игры с jni. В итоге при переносе достаточно почистить готовый код, логика (набор классов и методов для оберток, как в нативной части, так и в оболочке) остается прежний. Лично я считаю это преимуществом.

И если кол-во параметров можно сделать с запасом чтобы не переписывать при расширении, то вопрос с возвращаемыми значениями остается открытым. Скажем, у меня большинство каллбэков либо void, либо простые типы. Но есть и коллекции, и String. Возвращать Object для всех и получать из него простой тип в вызывающем коде каждого каллбэка - усложнение кода, как по мне

Я противник всяких фреймворков и тяжеловесных библиотек. Во-первых, все мои приложения весят считанные мегабайты, и я пребываю в откровенном недоумении когда вижу условный блокнот весом в 100мб. Во-вторых, я крайне не люблю брать сторонние библиотеки: это зависимость от чужого проекта, как от его дальнейшей поддержки, так и от лицензии и планов разработчика, которые могут измениться (допустим, решат брать плату за использование или кто-то их выкупит), исключением я считаю библиотеки криптопротоколов и тому прочее, что прямым образом связано с безопасностью. В-третьих (дополняя первый пункт), я сторонник минимализма: эффективно использовать память и дисковое пространство. В-четвертых, я уже создал собственные фреймворки для быстрого построения интерфейса под Java, Swift, gtk с одинаковым насколько это возможно API. Они хорошо протестированы и прекрасно работают, как и решение из статьи. Да, на это ушло время когда-то, зато теперь работать легко.

Опять же, я понимаю, что описанные выше пункты довольно дискуссионны, и многие компании прикручивают к своим проектам сотни библиотек ради одного единственного вызова и используют всевозможные фреймворки. Но, учитывая, что я занимаюсь собственными проектами, могу позволить себе путь, соответствующий моей идеологии :) Тем более, что именно за этим я и занялся программированием: чтобы решать интересные задачи, используя минимум.

Насчет эффективного использования дискового пространства и сторонних либ наброшу еще. Когда-то в своем сканере сети я реализовал функцию получения Netbios имен буквально в 20 строчек. На связь со мной вышел человек, который писал похожее приложение, чтобы узнать, как я это сделал, и по итогу... прикрутил библиотеку с полной поддержкой Samba протокола лишь ради этой функции. В дальнейшем, с доливанием собственной DNS либы для моих сетевых утилит, я усовершенствовал и эту функцию, тк там используется как раз DNS протокол, но вся моя собственная библиотека - это ~700 строчек.

За десктоп не скажу, этот подход для Android использую, где UI на java - не выбор, а данность. Для десктопных версий своих приложений пишу UI на C++, под gtk4.

Запоздало вспомнил еще одно преимущество моего метода: легкость переноса на другие системы. К примеру, С++ связывается со Swift без плясок с JNI, но общая структура кода остается похожей. Я просто беру, немного правлю нативный код, немного - код оболочки (да, перевод на другой язык, но логика сохраняется полностью), и вуаля - у меня уже аналогичные обертки под IOS. С протестированной логикой, что тоже весомый фактор по сравнению с тем, чтобы на каждой системе городить собственный огород и затем заново тестировать.

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

Не хочу оспаривать методы Google, но для собственных проектов мой вариант кажется мне красивее и удобнее, чем "портянки switch-case" и функция с кучей параметров. С точки зрения масштабирования - тоже. В проект могут добавляться новые классы с новыми листенерами, всякий раз менять кол-во параметров static функции и переписывать соответствующие участки кода? Не, я слишком ленив, да простит меня Гугл

Опять же, возвращаемое значение... Возвращать как Object, а потом плясать с бубном ради получения простого типа? Зачем, если большинство функций возвращают int, а одна-две - скажем, коллекцию или строку... в них как раз можно и заморочиться, а большую часть кода оставить простой и чистой

У меня в нэйтиве много классов с различными листенерами, с разным набором параметров и возвращаемых значений. В вашем примере придется делать отдельный NativeEvent для каждой функции (которых даже в одном отдельном листенере может быть больше одной). Да и самих листенеров может быть много - какие-то из них необязательные и тд. В общем, если листенер один с одной единственной функцией - ваше решение, пожалуй, и правда будет рациональнее. Если нативных классов много и у каждого свой листенер со своим набором функций - моя реализация кажется мне удобнее.

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

Спасибо за вопрос, возможно позже дополню статью пояснениями.

Information

Rating
Does not participate
Date of birth
Registered
Activity

Specialization

Десктоп разработчик, Разработчик мобильных приложений
Старший
C++
Java
Swift
SwiftUI
C
ООП