По-явански


Channel's geo and language: Russia, Russian
Category: Technologies


Статьи и новости, наблюдения, мысли и советы.
Кодревью: http://javanese.online/%D1%80%D0%B0%D0%B7%D0%B1%D0%BE%D1%80_%D0%BA%D0%BE%D0%B4%D0%B0/
Обсуждение в @javanese_questions
Материалы пишет @Harmonizr
Менеджер по рекламе: /dev/null

Related channels  |  Similar channels

Channel's geo and language
Russia, Russian
Statistics
Posts filter


Информационная политика наносит ответный кусь

1. Сотрудник компании А делает доклад о технологии Х. Она новая, очень интересная и многообещающая.
2. Сотрудники-энтузиасты компаний Бэ, Цэ и Дэ заинтересовываются технологией Х, выясняют, в каких ещё нишах её можно применить, и оформляют результаты в виде докладов на конференциях, митапах и стримах.
3. Обыкновенные™ работяги замечают волну интереса и делают пет-проекты с использованием технологии Х. Рынок наводняется специалистами, которые умеют и хотят использовать именно эту технологию.
4. Компании А, Бэ, Цэ, Дэ, а также невинные жертвы Йе и Эф вынуждены переписать всё на технологию Х, чтобы заинтересовывать и нанимать разработчиков.

5. Появляется технология Игрек. Сотрудник компании Бэ загорается энтузиазмом и делает доклад…

К слову, https://www.joelonsoftware.com/2002/01/06/fire-and-motion/


Нашёл детальную обучалку по Jetpack!
https://youtu.be/X9Rlst9NG5E?t=702


Об устройстве Gravity

Начнём с определения: грава эт короч в какую сторону вьюха липнет гравити описывает способ размещения одного прямоугольника внутри другого.

В константах гравити присутствуют любопытные танцы вокруг битиков, в которые с первого раза можно и не въехать, но на деле всё просто.

Для начала, задано две оси: на какую сам сядешь, на какую джуна посадишь?
public static final int AXIS_X_SHIFT = 0;
public static final int AXIS_Y_SHIFT = 4;
таким образом, флаги для обеих запечатываются в младший байт в форме 0bYYYYXXXX.

В каждой половинке размещается по четыре флага:
0001) указана ли вообще гравити для этой оси (экзотика)
0010) привязываться ли к началу оси
0100) привязываться ли к концу оси
1000) обрезать ли слишком большой прямоугольник
public static final int AXIS_SPECIFIED = 0x0001;
public static final int AXIS_PULL_BEFORE = 0x0002;
public static final int AXIS_PULL_AFTER = 0x0004;
public static final int AXIS_CLIP = 0x0008;

Основные значения гравити формулируются таким образом:
LEFT — липнуть к началу оси X,
RIGHT — липнуть к концу оси X,
TOP — к началу Y,
BOTTOM — к концу Y.
Одна константа для примера:
public static final int TOP =
(AXIS_PULL_BEFORE|AXIS_SPECIFIED)


:slowpoke: шикарный доклад про нутрянку корутин и способы их применения помимо асинхронности.

🟢 Разбор примитивов корутин из Kotlin stdlib
🟢 Как устроены билдеры вида sequence { yield() }
🟢 Глубокая рекурсия без отрыва стека
🟢 Парсеры

Friendly reminder разработчикам Kotlin:
⚫️ сиквенс — это бесполезная обёртка над итератором (в Rust её нет — компилятору легче оптимизировать и разворачивать длинные конструкции вида iter.map.filter.etc)
⚫️ DeepRecursiveScope.callRecursive стоило бы назвать invokeRecursive, консистентно с invoke и invokeSuspend, зашитыми в язык
⚫️ в очередной раз не хватает «:: наоборот» — fun smth() by DeepRecursiveFunction {}
Friendly reminder автору:
🟡 скоуп билдера должен быть @RestrictsSuspension
🟡 пожалуйста, не надо data-классов
Friendly reminder для организаторов:
💡 существуют нейросеточные плагины для убирания чвякания из речи


Year::(😘)


Как передать любой View произвольный AttributeSet

А зачем?
Есть атрибуты, которые можно выставить только из XML. Но не все вью удобно инстанцировать из XML, особенно когда это анонимный класс: addView(object : SomeView(context) { /* тут какие-то оверрайды */ }).

Сразу расстрою: программно создать AttributeSet, который будет работать с obtainStyledAttributes, не получится, если не прибегать к приватным API андроида.
В этом месте я и прекратил свои поиски, когда в 2016 начал верстать из кода.

Но можно любой вьюшке навязать атрибуты из layout-файла.
Например, такого:



Теперь парсим XML, пропускаем открывающий тэг и забираем атрибуты:
val parser = resources.getLayout(R.layout.scrollbars)
val attrs = Xml.asAttributeSet(parser)
advanceToRootNode(parser)
addView(object : SomeView(context, attrs) { /* тут какие-то оверрайды */ })
parser.close()

Исходник LayoutInflater::advanceToRootNode().


Телефон как USB-хаб с периферией

Когда-то давно мне срочно понадобился микрофон. Он есть в телефоне, но не было в компьютере. Накопал тогда mic over mumble, который после долгих уговоров заработал. Микрофон я потом купил, а потом ещё один 😌

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

Пробросить экран телефона можно с помощью scrcpy.

А почему так сложно? Я могу в настройках раздать вайфай, могу использовать телефон как USB-модем. Могу включить передачу файлов, отдав флешку в распоряжение компьютера.
Где тогда переключатель, который превратит телефон в веб-камеру и USB-микрофон? Удивительно, что это нужно как-то отдельно прокидывать через adb или Wi-Fi с помощью стороннего софта. Хочется, чтобы эти возможности были доступны не только гикам, но и бабушкам из глубинки.

И ещё: во всех мессенджерах можно показать экран, то есть пробросить сигнал с выхода на вход. Но почему нельзя пошарить выход аудиокарты? Хочу поставить музычку своим собеседникам!


Раздельная компиляция, min, compile, target

В целом Java-технологии привычные к раздельной компиляции. Серверные приложения компилируются с Java Class Library, которая подкладывается в compile classpath при сборке, а запускаются с другим экземпляром JCL, которая лежит на сервере.

Однако, эта раздельность почти не чувствуется. Она незримо присутствует и заключается в том, что в итоговом jar у нас не лежит весь java.lang, java.util и что мы там ещё любим. Мы запускаем приложение с той же версией JDK, с которой собирали, и всё просто работает.

Таким образом, приложение разрабатывается под одну версию платформы, без оглядки на более старые и с надеждой на совместимость с новыми.

В desktop-приложениях (кто-то их ещё пишет?) всё ещё проще: зачастую JVM приносят с собой, и раздельной компиляции как не бывало.

В Android же, как известно, зоопарк: на конечных устройствах много разных версий. И вот тут система сборки спроектирована очень удачно:
• compile SDK — последняя версия, известная разработчику приложения на момент сборки. Она подкладывается в compile classpath, за счёт чего разработчик видит все новые фичи платформы;
• min SDK — минимальная поддерживаемая версия. Старой платформе, которую разработчик не хочет поддерживать, позволяет отклонять установку приложений. Инструментарию позволяет подсказать программисту, что те или иные declarations недоступны в min и могут отсутствовать в runtime classpath, поэтому нужно обернуть их использование в if;
• target SDK — версия, на поведение которой рассчитывает приложение. Позволяет более новой версии платформы сохранить поведение старой в старом приложении.

Таким образом, в быстро меняющемся мире Android-приложение компилируется для свежей версии платформы (compile SDK), ифами поддерживает более старые версии (вплоть до min SDK), а платформа, если она новее, чем ожидаемая (target SDK), сохраняет старое совместимое поведение (тоже ифами).

Это прекрасно. Это шедевр.

Для сравнения, ситуация в мире плагинов для IntelliJ: выбираешь одну версию, которая и будет твоим compile и min. Хочешь поддержать постарше — опускаешь версию, перестаёшь видеть новые declarations. Если в новых версиях что-то deprecated — ты об этом узнаешь на этапе валидации плагина, где-то после компиляции и упаковки.

Именно поэтому при обновлении IDE плагины часто либо отключаются (разработчик указал максимальную поддерживаемую версию), либо разваливаются (мой вариант:).

Зависишь от других плагинов? Вообще страдай. Там может быть установлена любая версия. Например, если зависишь от Android-плагина для IDE, то при компиляции видишь версию, которой полгода, а в бетах Android Studio уже много раз переименовали классы, поменяли на интерфейсы, переместили в другой пакет. (И сделали это в стенах той же компании, где придумали min, compile, target.) Удачи!


Размножение массивов

String::repeat — произведение искусства.

Arrays.fill же написан банально и буднично, но я подозреваю, что он успешно векторизуется.


Пару слов про зерокодинг и ни одной шутки про зерозарплатинг

Да, из готовых компонентов можно собрать сайт, приложение или круд. Оно даже будет работать. Я смотрю на это просто как на программирование на более высоком уровне.

Что здесь примечательно для нас, разработчиков? А то, что компоненты «среднего» уровня написаны такими же программистами. И если менеджер мышкой натыкивает приложение быстрее, чем профессиональный разработчик, то у нас, коллеги, наблюдается проблема с job security качеством и доступностью компонентов. Если OAuth из конструктора интегрируется быстрее и работает лучше, чем решение с гитхаба, значит, мы залайкали не тот репозиторий, автор его недодокументировал или вообще бросил на полпути. Если нам данные приходят по одной схеме, и мы, чтобы трансформировать их в другую, удобную нам, выражаем обе через ДТОшки и пишем маппер между ними, значит, библиотека, которой мы намазываем данные на классы, не решает нашу задачу. Если прокладка для работы с БД заставляет нас… ну и так далее.

Зерокодинг никогда не станет мощнее и гибче, чем «настоящее» программирование. А наша задача — делать так, чтобы последнее не отставало по скорости и качеству. Хочу надеяться, что конкуренция со стороны зерокодинга поспособствует повышению качества нашего родного программирования.




Если вы когда-нибудь искали способ поставить бряку для одного конкретного экземпляра, то… вот он!


Привет, я подсяду? Поговорим о корпоративной коррупции?

Давайте разберёмся, как в опенсорс попадают всякие технологии. Вот мне кусочек рационального мышления подсказывает, что компания решает свои задачи, свои проблемы, выпускает что-то для себя, внедряет технологию в свои процессы, извлекает из этого коммерческую выгоду, и — почему бы нет — делится с другими, собирая багрепорты от широкой аудитории и повышая качество — а это снова выгода. Ну, логично, мне кажется. Вроде как-то так должно работать.

Теперь давайте прикола ради глянем библиотеку, которая не работает: она должна помогать следить за внешним видом приложения, но даже стандартную кнопочку со стандартным stateListAnimator'ом в дефолтной теме скриншотит неправильно, не говоря уже про скруглённые аватарки, которые у них в собственном приложении таки есть, судя по нагугленным скриншотам.

Чистая прибыль в 23 гигабакса даёт о себе знать, нужно срочно стартовать новый проект, обосновать его целесообразность, выбить финансирование. Написанный код потом можно выкинуть — не прижился.

Ах да. PixelCopy.request. Шах и мат, аферисты.


ой


Редактируемый список — EditText внутри RecyclerView

Очень много лулзов на StackOverflow по этому вопросу. Написать адаптер с эдиттекстами под силу каждому, а вот получить назад отредактированные данные могут не только лишь все.

Рассмотрим для начала очевидно нерабочий способ: for-each по вьюшечкам. Как ни странно, я видел такое решение в продакшене. Чтобы оно работало, ресайклер был завёрнут в скроллвью!

Следующий сомнительный вариант: нацепить TextWatcher и записывать результат Editable.toString() на каждый тык пользователя по клавиатуре.

Название Editable, кстати, намекает нам на мутабельность редактируемого буфера. Так возникает ещё одна стратегия — дёрнуть Editable getText(), а не слушать каждое изменение. Тогда байндинг будет выглядеть так:
editText.setText(editables[position] ?: strings[position])
editables[position] = editText.text

EditText создаст мутабельную копию строки. А можно сделать это самостоятельно, потому что в editables уже может лежать нужный буфер. Только нужно отвадить EditText от копирования, заменив Editable.Factory.
Итоговый gist и ответ на SO.


Недавно меня посетила красивая #идея — вот бы приложения карт умели показывать слои, предоставленные другими приложениями! Открываешь Organic, 2GIS или что там сейчас есть из картографии — а туда сразу подтягиваются такси, самокаты, каршеринг, общественный транспорт, парковки — в зависимости от того, какие провайдеры установлены. Философия UNIX во всей красе.

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


Интерфейсы коллекций

Вчера задали мне этот вопрос на собесе. Ну я и перечисляю: Iterable, Collection, List, Set, SortedSet, NavigableSet, Queue, Deque; Map, ConcurrentMap — тут остановился в ожидании реакции собеседующего. Глазами хлопаю, мол, что, надо ещё?

Оказывается, это почти всё. Для пущего эффекта можно выучить: BlockingQueue, TransferQueue, BlockingDeque; SortedMap, NavigableMap, ConcurrentNavigableMap.


Опаньки, оказывается, из типового параметра можно убрать нуллабельность (подсветка синтаксиса тоже удивлена).

Пример
KEEP — за ссылку спасибо @r4zzz4k


Forward from: Android Broadcast
🔴 Стартует собеседование в прямом эфире

Проводит Михаил Горюнов @Harmonizr, разработчик Android-приложений, библиотек и инструментов.

Миша будет собеседовать на позицию Android разработчика без уровня (требования здесь)

P.S. Запись останется на канале

#AndroidBroadcast #собеседование


Парсинг ботокоманд

/add_thing Name Description
/add_thing Name 'Long description'

Как распарсить эти команды и не сойти с ума? Внутри JDK периодически используется StringTokenizer, но это просто String.split() образца 1995 года. А нужный класс, который понимает кавычки, называется StreamTokenizer, и, как следует из названия, он ещё и стрим разобрать может.

20 last posts shown.