Сложно понять, что сподвигло архитекторов на подобное решение
Я тоже над этим размышлял, думаю это по большей части связано с 2 проблемами:
1) Что делать, если Activity имеет разные ресурсы для портрета и лендскейпа. С одной стороны, наверно можно было бы сделать какое-то отдельное АПИ, чтобы обрабатывать эти случаи. Но тогда жизненный цикл отличался бы для Activity с разными ресурсами, что довольно неудобно.
2) Есть много других ситуаций, когда Activity меняет конфигурацию и тоже пересоздается. Но они менее очевидные и частые, чем простой поворот экрана. Возможно архитекторы хотели таким образом зафорсить обработку всех подобных случаев, чтобы разработчики на оставляли баги.
Может есть еще какие-то более глубокие причины, систему очень давно начали писать.
Ну а в целом архитектура говно, да.
Но перечисленные проблемы очень базовые и все уже как-то научились с этим жить, используя либы, наработки умных дядек и правильные подходы к написанию кода.
Довольно спорное утверждение.
Не знаю как там в iOS и Flutter, но если бы в Андроиде не было автоматического сохранения состояния вьюх, фрагментов, стека активити и прочего-прочего, было бы очень больно жить.
Соответственно хотелось бы, чтобы Flutter тоже умел все сохранять так, как это делает нативный SDK.
Здесь речь не о персистентности, а о сохранении состояния между переходами в жизненном цикле компонентов.
Да и RecyclerView тоже не сохранил бы позицию скролла автоматически.
Это распространенное заблуждение. RecyclerView, как и любой другой скроллящийся контейнер в Андроиде, сохраняет свою позицию скролла автоматически при наличии id. Затем во время первого onLayout он пытается в эту позицию проскроллить. Если к этому моменту не передать данные, позиция потеряется. Конкретно у RecyclerView этим всем занимается LayoutManager, можете посмотреть сырцы.
Причина, по которой у вас это не работает, кроется в том, что вы неправильно передаете данные адаптеру после переворота экрана (или don't keep activities). Скорее всего у вас используется что-то типа handler.post(this::setData), возможно неявно, поэтому данные прилетают после первого onLayout.
Свет не тормозится гравитацией, вместо этого он меняет длину волны, и следует траектории кривизны пространства, порождаемой массивным объектом. Но то, что траектория «кривая», не значит, что свет проделывает больший путь. Он всегда движется по прямой, просто при такой кривизне пространства, прямая может быть изогнутой.
Как пример, можно взять листик, нарисовать на нем прямую, а потом согнуть его. Прямая не поменяет свою длину от этого, но визуально станет кривой.
Не минусовал, но конкретно я бы предпочел мокать final класс, чем создавать бесполезный интерфейс с одной реализацией, только для того, чтобы мокать его в тестах.
То есть я бы сказал, что просветом в дизайне являются скорее такие интерфейсы, если на их существование нет никакой другой весомой причины (например, скрыть платформо-зависимые компоненты).
Ну а открывать класс только для того, чтобы его можно было мокнуть без Mockito 2 — тоже не сильно хорошо.
Как Вы думаете, стоит ли помещать во ViewHolder основные методы?
Я думаю вообще не стоило делать такого рода ViewHolder. Получается, сломали стандартный ViewHolder, накостылили поверх кэш и теперь в каждом холдере есть лишний SparseArray, а в итоге эта конструкция для байндинга вида
При этом даже написав 1000 методов для удобства, все равно не покроете все возможные случаи байндинга ячейки.
Есть, кстати, либа, которая работает примерно по такому принципу: github.com/MEiDIK/SlimAdapter
Если посмотреть на современные клавиатуры, то обычно ввод данных сканируется с частотой от 100 Гц до 200 Гц
Понимаю, что это перевод, но чисто для уточнения:
есть много клавиатур, у которых частота опроса 1000Гц. Еще некоторое время назад читал статью, в которой тестировали Apple Magic Keyboard, и оказалось, что у них отклик быстрее чем у большинства разрекламированных механических клавиатур.
Так что справедливости ради, надо бы взять нормальную клавиатуру для теста.
Стоит упомянуть, что если Inner класс обращается к приватным полям или методам внешнего класса, компилятор генерирует synthetic accessor метод с package модификатором видимости, чтобы тот в свою очередь мог достучаться до приватного метода.
Таким образом, если вы вызывате приватный метод внешнего класса, вы на самом деле вызываете 2 метода, accessor и тот, к которому требуется доступ.
Сделано это потому, что в Java после компиляции нет понятия Inner класса. Inner класс всего лишь станет package классом в том же пакете, рядом с внешним классом.
Что именно будет работать только на Android Studio 3.0?
Шрифты работают на уровне Compat либы (или SDK в случае 26+), Android Studio здесь вообще не при чем.
В общем-то проект можно вообще с консоли собрать и шрифты будут прекрасно работать.
Но в то же время они его облегчают путем отбрасывания поддержки старых SDK.
Да и в общем-то кода там немного, а Room идет отдельно.
Собственно, Lifecycle тоже сейчас отдельно, но это, как я понимаю, временно.
Не считаю язык плохим, но в принципе, с каждым приведенным аргументом согласен, тоже раздражают эти вещи жутко.
Мне непонятно главным образом 2 вещи:
1) Зачем делать что-то хуже, чем уже было в Java (for, ?: оператор, приведение типов и т.д.)
2) Почему создатели языка считают, что только компилятор должен решать как обезопасить код, а не программист?
Серьезно, эта ошибка просто мозг выносит.
Smart cast to 'Int' is impossible, because 'value' is a mutable property that could have been changed by this time.
Я знаю про более идиоматический вариант с ?.let{ }, но не считаю, что в таких ситуациях этот подход повышает читаемость, за что так борется Kotlin.
Существует пул из TypedArray.
Если вы не сделаете ресайкл, системе ресурсов позже придется создать и добавить новый TypedArray в пул. Если заресайклить, то TypedArray можно будет переиспользовать.
Небольшая оптимизация по памяти.
Я тоже над этим размышлял, думаю это по большей части связано с 2 проблемами:
1) Что делать, если Activity имеет разные ресурсы для портрета и лендскейпа. С одной стороны, наверно можно было бы сделать какое-то отдельное АПИ, чтобы обрабатывать эти случаи. Но тогда жизненный цикл отличался бы для Activity с разными ресурсами, что довольно неудобно.
2) Есть много других ситуаций, когда Activity меняет конфигурацию и тоже пересоздается. Но они менее очевидные и частые, чем простой поворот экрана. Возможно архитекторы хотели таким образом зафорсить обработку всех подобных случаев, чтобы разработчики на оставляли баги.
Может есть еще какие-то более глубокие причины, систему очень давно начали писать.
Ну а в целом архитектура говно, да.
Но перечисленные проблемы очень базовые и все уже как-то научились с этим жить, используя либы, наработки умных дядек и правильные подходы к написанию кода.
Не знаю как там в iOS и Flutter, но если бы в Андроиде не было автоматического сохранения состояния вьюх, фрагментов, стека активити и прочего-прочего, было бы очень больно жить.
Соответственно хотелось бы, чтобы Flutter тоже умел все сохранять так, как это делает нативный SDK.
Здесь речь не о персистентности, а о сохранении состояния между переходами в жизненном цикле компонентов.
Это распространенное заблуждение. RecyclerView, как и любой другой скроллящийся контейнер в Андроиде, сохраняет свою позицию скролла автоматически при наличии id. Затем во время первого onLayout он пытается в эту позицию проскроллить. Если к этому моменту не передать данные, позиция потеряется. Конкретно у RecyclerView этим всем занимается LayoutManager, можете посмотреть сырцы.
Причина, по которой у вас это не работает, кроется в том, что вы неправильно передаете данные адаптеру после переворота экрана (или don't keep activities). Скорее всего у вас используется что-то типа handler.post(this::setData), возможно неявно, поэтому данные прилетают после первого onLayout.
У меня есть небольшой пост на эту тему.
Как пример, можно взять листик, нарисовать на нем прямую, а потом согнуть его. Прямая не поменяет свою длину от этого, но визуально станет кривой.
То есть я бы сказал, что просветом в дизайне являются скорее такие интерфейсы, если на их существование нет никакой другой весомой причины (например, скрыть платформо-зависимые компоненты).
Ну а открывать класс только для того, чтобы его можно было мокнуть без Mockito 2 — тоже не сильно хорошо.
Ну всё-таки в Mockito 2 final классы мокаются без проблем.
Я думаю вообще не стоило делать такого рода ViewHolder. Получается, сломали стандартный ViewHolder, накостылили поверх кэш и теперь в каждом холдере есть лишний SparseArray, а в итоге эта конструкция для байндинга вида выглядит ничем не лучше, чем ViewHolder с полями.
При этом даже написав 1000 методов для удобства, все равно не покроете все возможные случаи байндинга ячейки.
Есть, кстати, либа, которая работает примерно по такому принципу: github.com/MEiDIK/SlimAdapter
Понимаю, что это перевод, но чисто для уточнения:
есть много клавиатур, у которых частота опроса 1000Гц. Еще некоторое время назад читал статью, в которой тестировали Apple Magic Keyboard, и оказалось, что у них отклик быстрее чем у большинства разрекламированных механических клавиатур.
Так что справедливости ради, надо бы взять нормальную клавиатуру для теста.
Вот есть отличный доклад, но тут не только Котлин и лямбды рассматриваются.
skillsmatter.com/skillscasts/10012-keynote-sinking-your-teeth-into-bytecode
Таким образом, если вы вызывате приватный метод внешнего класса, вы на самом деле вызываете 2 метода, accessor и тот, к которому требуется доступ.
Сделано это потому, что в Java после компиляции нет понятия Inner класса. Inner класс всего лишь станет package классом в том же пакете, рядом с внешним классом.
Шрифты работают на уровне Compat либы (или SDK в случае 26+), Android Studio здесь вообще не при чем.
В общем-то проект можно вообще с консоли собрать и шрифты будут прекрасно работать.
Да и в общем-то кода там немного, а Room идет отдельно.
Собственно, Lifecycle тоже сейчас отдельно, но это, как я понимаю, временно.
Я конкретно про вышеупомянутый пример.
Мне непонятно главным образом 2 вещи:
1) Зачем делать что-то хуже, чем уже было в Java (for, ?: оператор, приведение типов и т.д.)
2) Почему создатели языка считают, что только компилятор должен решать как обезопасить код, а не программист?
Серьезно, эта ошибка просто мозг выносит.
Smart cast to 'Int' is impossible, because 'value' is a mutable property that could have been changed by this time.
Я знаю про более идиоматический вариант с ?.let{ }, но не считаю, что в таких ситуациях этот подход повышает читаемость, за что так борется Kotlin.
Если вы не сделаете ресайкл, системе ресурсов позже придется создать и добавить новый TypedArray в пул. Если заресайклить, то TypedArray можно будет переиспользовать.
Небольшая оптимизация по памяти.
Что не работает? Установка шрифта для кастомного аттрибута?
https://github.com/lisawray/fontbinding
Не надо наследоваться, нет зависимости от конкретной реализации TextView, не надо каждый раз писать boilerplate
Как насчет хранить его в lastCustomNonConfigurationInstance?