Javanese Online
**Описание на 450 символов для Telegram канала "Javanese Online":** Добро пожаловать в канал "Javanese Online"! Здесь вы найдете самые интересные статьи, новости, наблюдения и советы, связанные с языком программирования Java. Мы постоянно обновляем канал, чтобы предоставить вам актуальную информацию о последних тенденциях и разработках в мире Java. Независимо от вашего уровня опыта, вы найдете полезные материалы, которые помогут вам расширить свои знания и навыки в программировании на Java. Мы стремимся создать сообщество, где вы сможете обмениваться своими идеями, задавать вопросы и получать ответы от опытных профессионалов. Присоединяйтесь к "Javanese Online", чтобы оставаться в курсе последних новостей и развиваться вместе с нами в мире Java!
Информационная политика наносит ответный кусь
1. Сотрудник компании А делает доклад о технологии Х. Она новая, очень интересная и многообещающая.
2. Сотрудники-энтузиасты компаний Бэ, Цэ и Дэ заинтересовываются технологией Х, выясняют, в каких ещё нишах её можно применить, и оформляют результаты в виде докладов на конференциях, митапах и стримах.
3. Обыкновенные™ работяги замечают волну интереса и делают пет-проекты с использованием технологии Х. Рынок наводняется специалистами, которые умеют и хотят использовать именно эту технологию.
4. Компании А, Бэ, Цэ, Дэ, а также невинные жертвы Йе и Эф вынуждены переписать всё на технологию Х, чтобы заинтересовывать и нанимать разработчиков.
5. Появляется технология Игрек. Сотрудник компании Бэ загорается энтузиазмом и делает доклад…
К слову, https://www.joelonsoftware.com/2002/01/06/fire-and-motion/
Joel on Software
Fire And MotionSometimes I just can’t get anything done. Sure, I come into the office, putter around, check my email every ten seconds, read the web, even do a few brainless tasks like paying the American E…
Нашёл детальную обучалку по 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)<<AXIS_Y_SHIFT;
У CENTER в жизни отсутствует стремление к какой бы то ни было оси, FILL же склоняется к обеим. На примере горизонтали:
public static final int CENTER_HORIZONTAL =
AXIS_SPECIFIED<<AXIS_X_SHIFT;
public static final int FILL_HORIZONTAL =
LEFT|RIGHT;
Для тех, кто впервые видит FILL, есть ещё один сюрприз:
public static final int CLIP_HORIZONTAL =
AXIS_CLIP<<AXIS_X_SHIFT;
Это размещение по центру с обрезкой краёв.
Если скомбинировать это значение, например, с LEFT, то размещение будет уже слева, с обрезкой правого края.
FILL и CLIP по обеим осям просто содержат оба набора флагов:
public static final int CENTER =
CENTER_VERTICAL|CENTER_HORIZONTAL;
public static final int FILL =
FILL_VERTICAL|FILL_HORIZONTAL;
(Бесполезный факт:
CENTER_VERTICAL == CENTER_HORIZONTAL>>AXIS_X_SHIFT<<AXIS_Y_SHIFT
и наоборот, и так далее, и тому подобное.)Остались START и END — начало и конец строки с учётом направления письма. Нет, прости, шупай, татэгаки и сероссыги, но это работает только по горизонтали.
Получается добавлением к LEFT и RIGHT флажка «ось X задана относительно layout direction»:
public static final int RELATIVE_LAYOUT_DIRECTION =
0x00800000;
public static final int START =
RELATIVE_LAYOUT_DIRECTION | LEFT;
Итого:
struct Gravity {
relative: bool,
axisX: AxisGravity,
axisY: AxisGravity,
}
struct AxisGravity {
specified: bool,
pullBefore: bool,
pullAfter: bool,
clip: bool,
}
Здесь я не упоминаю про флаги DISPLAY_CLIP, потому что обычно оно не надо.
В классе Gravity есть методы apply, которые разбирают этот набор флагов и выполняют размещение — в простых случаях этого хватает с головой.
Для случаев, когда нужно потрогать гравити самостоятельно — наконец-то, раздел с практическими советами!
1. Фильтруем входные данные линтом.
@Gravity.GravityFlags
недоступен, да и DISPLAY_CLIP из него нам не нужóн — но можно пойти и объявить собственный набор разрешённых флагов:@IntDef(flag = true, value = {
FILL, FILL_HORIZONTAL, FILL_VERTICAL,
START, END, LEFT, RIGHT, TOP, BOTTOM,
CENTER, CENTER_HORIZONTAL, CENTER_VERTICAL,
CLIP_HORIZONTAL, CLIP_VERTICAL,
})
public @interface GravityFlags {}
2. Иногда нужно просто выбрать сторону, поэтому недавно у меня появилось такое:
@IntDef({ START, END, LEFT, RIGHT, TOP, BOTTOM })
public @interface SideGravity { }
3. Потенциально относительную граву можно легко превратить в абсолютную посредством
Gravity.getAbsoluteGravity(gravity, layoutDirection)
. Тогда, например, @SideGravity
сузится до простого набора { LEFT, TOP, RIGHT, BOTTOM }
.Нет, можно, конечно, написать
sealed class Gravity {
sealed class Absolute : Gravity()
sealed class Relative : Gravity() {
abstract fun absolute(dir: Int): Absolute
}
object ...
}
Это будет корректно и безопасно. Но громоздко и лень!
: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 для организаторов:
💡 существуют нейросеточные плагины для убирания чвякания из речи
YouTube
Coroutines Beyond Concurrency by Alex SeminRecording brought to you by American Express. https://americanexpress.io/kotlin-jobs
Kotlin coroutines are most known as an elegant and modern solution for managing asynchronous work. But due to their versatile design, coroutines can also be helpful for…
Year::<init>(😘)
Как передать любой View произвольный AttributeSet
А зачем?
Есть атрибуты, которые можно выставить только из XML. Но не все вью удобно инстанцировать из XML, особенно когда это анонимный класс: addView(object : SomeView(context) { /* тут какие-то оверрайды */ })
.
Сразу расстрою: программно создать AttributeSet
, который будет работать с obtainStyledAttributes
, не получится, если не прибегать к приватным API андроида.
В этом месте я и прекратил свои поиски, когда в 2016 начал верстать из кода.
Но можно любой вьюшке навязать атрибуты из layout-файла.
Например, такого:
<?xml version="1.0" encoding="utf-8"?>
<View
xmlns:android="http://schemas.android.com/apk/res/android"
android:scrollbars="horizontal" />
Теперь парсим XML, пропускаем открывающий тэг и забираем атрибуты:
val parser = resources.getLayout(R.layout.scrollbars)
val attrs = Xml.asAttributeSet(parser)
advanceToRootNode(parser)
addView(object : SomeView(context, attrs) { /* тут какие-то оверрайды */ })
parser.close()
Исходник LayoutInflater::advanceToRootNode().
GitHub
platform_frameworks_base/core/java/android/view/LayoutInflater.java at ac5f755472e02f039f947ccfd5f5282e0ac80fe3 · aosp-mirror/…Contribute to aosp-mirror/platform_frameworks_base development by creating an account on GitHub.
Телефон как 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 из конструктора интегрируется быстрее и работает лучше, чем решение с гитхаба, значит, мы залайкали не тот репозиторий, автор его недодокументировал или вообще бросил на полпути. Если нам данные приходят по одной схеме, и мы, чтобы трансформировать их в другую, удобную нам, выражаем обе через ДТОшки и пишем маппер между ними, значит, библиотека, которой мы намазываем данные на классы, не решает нашу задачу. Если прокладка для работы с БД заставляет нас… ну и так далее.
Зерокодинг никогда не станет мощнее и гибче, чем «настоящее» программирование. А наша задача — делать так, чтобы последнее не отставало по скорости и качеству. Хочу надеяться, что конкуренция со стороны зерокодинга поспособствует повышению качества нашего родного программирования.
Один мой коллега постоянно забывал, как кого зовут, из-за чего в нашем лексиконе появились два собирательных персонажа — Кирилл Гладков и Алексей Розов.
Дошутились таки!
Telegram
Mobile DeveloperОчень важный анонс! 🔥🔥
Mobile Developer и Android Broadcast идут в оффлайн!
После нашего с Кириллом турне по России мы поняли, что во многих городах есть люди, которые хотели бы встречаться, общаться и обмениваться знаниями без деления на платформы, а просто…
Если вы когда-нибудь искали способ поставить бряку для одного конкретного экземпляра, то… вот он!
Привет, я подсяду? Поговорим о корпоративной коррупции?
Давайте разберёмся, как в опенсорс попадают всякие технологии. Вот мне кусочек рационального мышления подсказывает, что компания решает свои задачи, свои проблемы, выпускает что-то для себя, внедряет технологию в свои процессы, извлекает из этого коммерческую выгоду, и — почему бы нет — делится с другими, собирая багрепорты от широкой аудитории и повышая качество — а это снова выгода. Ну, логично, мне кажется. Вроде как-то так должно работать.
Теперь давайте прикола ради глянем библиотеку, которая не работает: она должна помогать следить за внешним видом приложения, но даже стандартную кнопочку со стандартным stateListAnimator'ом в дефолтной теме скриншотит неправильно, не говоря уже про скруглённые аватарки, которые у них в собственном приложении таки есть, судя по нагугленным скриншотам.
Чистая прибыль в 23 гигабакса даёт о себе знать, нужно срочно стартовать новый проект, обосновать его целесообразность, выбить финансирование. Написанный код потом можно выкинуть — не прижился.
Ах да. PixelCopy.request
. Шах и мат, аферисты.
GitHub
View clipping to outline doesn't work on screenshots · Issue #276 · facebook/screenshot-tests-for-androidWhen make a screenshot test for some layout, and some custom view inside contains outline clipping like that: view.outlineProvider = object : ViewOutlineProvider() { override fun getOutline(v: View...
IllegalStateException: cannot make a new request because the previous response is still open: please call response.close() Занятный крэш меня сегодня посетил. Типовое обновление токена. Нетрудно понять, где именно баг, но как именно вы бы его чинили?
ой
Редактируемый список — EditText
внутри RecyclerView
Очень много лулзов на StackOverflow по этому вопросу. Написать адаптер с эдиттекстами под силу каждому, а вот получить назад отредактированные данные могут не только лишь все.
Рассмотрим для начала очевидно нерабочий способ: for-each по вьюшечкам. Как ни странно, я видел такое решение в продакшене. Чтобы оно работало, ресайклер был завёрнут в скроллвью!
Следующий сомнительный вариант: нацепить TextWatcher
и записывать результат Editable.toString()
на каждый тык пользователя по клавиатуре.
Название Editable
, кстати, намекает нам на мутабельность редактируемого буфера. Так возникает ещё одна стратегия — дёрнуть Editable getText()
, а не слушать каждое изменение. Тогда байндинг будет выглядеть так:editText.setText(editables[position] ?: strings[position])
editables[position] = editText.textEditText
создаст мутабельную копию строки. А можно сделать это самостоятельно, потому что в editables
уже может лежать нужный буфер. Только нужно отвадить EditText
от копирования, заменив Editable.Factory
.
Итоговый gist и ответ на SO.
Gist
Another approach to EditTexts inside RecyclerViewAnother approach to EditTexts inside RecyclerView. GitHub Gist: instantly share code, notes, and snippets.
Недавно меня посетила красивая #идея — вот бы приложения карт умели показывать слои, предоставленные другими приложениями! Открываешь Organic, 2GIS или что там сейчас есть из картографии — а туда сразу подтягиваются такси, самокаты, каршеринг, общественный транспорт, парковки — в зависимости от того, какие провайдеры установлены. Философия UNIX во всей красе.
Как и большинство других идей, я не первый, к кому они приходят. Например, есть вот такая закрытая/коммерческая интеграция. А хочется — публичный интерфейс для всех.
Интерфейсы коллекций
Вчера задали мне этот вопрос на собесе. Ну я и перечисляю: Iterable
, Collection
, List
, Set
, SortedSet
, NavigableSet
, Queue
, Deque
; Map
, ConcurrentMap
— тут остановился в ожидании реакции собеседующего. Глазами хлопаю, мол, что, надо ещё?
Оказывается, это почти всё. Для пущего эффекта можно выучить: BlockingQueue
, TransferQueue
, BlockingDeque
; SortedMap
, NavigableMap
, ConcurrentNavigableMap
.
Опаньки, оказывается, из типового параметра можно убрать нуллабельность (подсветка синтаксиса тоже удивлена).
Пример
KEEP — за ссылку спасибо @r4zzz4k
Forwarded From Android Broadcast (Кирилл Розов)
🔴 Стартует собеседование в прямом эфире
Проводит Михаил Горюнов @Harmonizr, разработчик Android-приложений, библиотек и инструментов.
Миша будет собеседовать на позицию Android разработчика без уровня (требования здесь)
P.S. Запись останется на канале
#AndroidBroadcast #собеседование