Страницы

Поиск по вопросам

вторник, 9 октября 2018 г.

ListView vs RecyclerView

Не так давно начал писать под android и использовал всегда ListView, после чего отдал свой код на проверку и мне сказали что использовать ListView "не камильфо", увы не обосновали почему. Чем они так кординально отличаются и чем RecyclerView лучше ListView?


Ответ

RecyclerView новый вид ViewGroup подготовленный для интерпретации одинаковым способом любых view использующих адаптеры . Предполагается, что он будет наследником ListView и GridView. Одна из причин заключается в том, что RecyclerView имеет более расширяемый фрэймворк, тем более что он предоставляет возможность осуществлять как горизонтальную, так и вертикальную компоновку. Используйте RecyclerView когда у вас есть наборы данных, элементы которого меняются во время выполнения на основе действий пользователя или событий сети.
RecyclerView отличается от своего предшественника Listview в первую очередь из-за следующих особенностей:
1) необходимость применения ViewHolder в адаптере - адаптеры Listview не требуют использования паттерна ViewHolder для повышения производительности. В отличие от этого, исполнение адаптера для RecyclerView требует использования паттерна ViewHolder;
2) Настраиваемые слои элементов - Listview может располагать элементы только в вертикальном линейном порядке и это не может быть изменено. В отличие от Listview ,RecyclerView имеет RecyclerView.Layoutmanager, который позволяет любое размещение элементов, включая горизонтальные списки или сетки в шахматном порядке;
3) Легкая анимация элементов - Listview не содержит никаких специальных механизмов, посредством которых можно анимировать добавление или удаление элементов. В отличие от Listview ,RecyclerView имеет RecyclerView.ItemAnimator, который позволяет управлять анимацией;
4) Устанавливаемый вручную источник данных - в Listview были адаптеры для различных источников, таких как адаптер массива и CursorAdapter для массивов и базы данных соответственно. В отличие от них RecyclerView.Adapter требует пользовательской реализации доставки данных к адаптеру;
5) Ручное декорирование элементов – ListView имеет android:divider для легкого разделения элементов в списке. В отличие от Listview ,RecyclerView имеет RecyclerView.ItemDecoration, который обеспечивает более широкие возможности по декорированию разделения;
6) Определение нажатия на элемент - ListView имеет AdapterView.OnItemClickListener интерфейс для связывания событий нажатия с конкретным элементом списка. В отличие от Listview ,RecyclerView поддерживает только RecyclerView.OnItemTouchListener который управляет отдельными событиями нажатия, но не имеет встроенного управления нажатием.

Почему не рекомендуется писать строчки кода длиннее 80 символов?

Недавно решил ознакомиться с распространёнными стандартами форматирования кода, и первой под руку попалась Oracle Code Conventions, все рекомендации из которой выглядят всесьма логично. Кроме одной: Avoid lines longer than 80 characters, since they're not handled well by many terminals and tools. Казалось бы, век алфавитно-цифровых мониторов с разрешением 25 * 80 символов давно сменился веком широкоформатных дисплеев. И почему бы теперь не увеличить границу до приемлемых масштабов, сохранив несчастные строчки нераздробленными? Есть ли у рекомендации другие причины оставаться актуальной, или её лучше игнорировать?


Ответ

Эта рекомендация работает при печати исходников на бумагу. Для печати исходников используется моноширинный шрифт типа Courier. Обычно все IDE исторически настроены при печати на бумагу на определенный размер шрифта под те самые 80 символов. Если вы не намерены постоянно печатать исходники и потом изучать это в метро по пути домой или дома в заведении МЖ - то можно забыть об этом. Я лично уже давно плюю на ширину 80.

Java реализация суммы прописью

Существует ли библиотечная реализация перевода суммы в слова на русском языке? Если нет, то как реализовать оптимальным способом?


Ответ

Можете воспользоваться готовой библиотекой Icu4j
RuleBasedNumberFormat nf = new RuleBasedNumberFormat(Locale.forLanguageTag("ru"), RuleBasedNumberFormat.SPELLOUT); System.out.println(nf.format(1234567)); // один миллион двести тридцать четыре тысячи пятьсот шестьдесят семь
RuleBasedNumberFormat nf = new RuleBasedNumberFormat(Locale.forLanguageTag("pl"), RuleBasedNumberFormat.SPELLOUT); System.out.println(nf.format(1234567)); // jeden milion dwieście trzydzieści cztery tysiące pięćset sześćdziesiąt siedem
RuleBasedNumberFormat nf = new RuleBasedNumberFormat(Locale.forLanguageTag("en"), RuleBasedNumberFormat.SPELLOUT); System.out.println(nf.format(1234567)); // one million two hundred thirty-four thousand five hundred sixty-seven
RuleBasedNumberFormat nf = new RuleBasedNumberFormat(Locale.forLanguageTag("de"), RuleBasedNumberFormat.SPELLOUT); System.out.println(nf.format(1234567)); // eine Million zwei-hundert-vier-und-dreißig-tausend-fünf-hundert-sieben-und-sechzig

Почему все пишут приложения на WinForms если WPF лучше? [закрыт]

Очень часто на этом форуме встречаются вопросы которые начинаются таким образом
Я пишу приложение на WinForms. [...]
Я лично пробовал писать на Win Form и на WPF, и, как мне показалось, WPF более точный, более красивый в плане дизайна UI элементов. К тому же, в комплекте в WPF идёт замечательнейший язык Xaml, с которым работать намного легче чем с C# кодом внутри WinForms.
В связи с этим и задаюсь вопросом: какие преимущества есть у Win Form перед WPF и почему многие пишут на Win Form, хотя у них устарелый дизайн и они не поддерживаются?


Ответ

У WPF и правда масса преимуществ перед WinForms. Особенно серьёзным преимуществом я бы назвал понятие привязки (Binding) и DataContext, которые радикально облегчают написание правильно структурированных программ, в которых представление отделено от модели, бизнес-логики и контента.
(Не то, чтобы на WinForms невозможно было писать правильно, это намного сложнее, и требует ручной работы.)
Но следствием этого и обратной стороной является гораздо более высокая сложность WPF как фреймворка, намного более высокий порог вхождения в WPF и в правильные методики программирования на нём. Ведь сила WPF проявляется именно когда вы начинаете отделять контент от представления, без этого он ненамного лучше WinForms.
Тем, у кого есть опыт программирования на MFC или похожих UI-фреймворках, намного легче перейти на практически аналогичный WinForms, чем учить новые (хотя бы и более удобные и продуктивные) концепции, которые помогают лёгкому, удобному программированию на WPF.
Думаю, именно это является основной причиной того, что WinForms всё ещё существует.

Include в заголовочных файлах

Заметил, что в разных проектах C++ программисты по разному используют директиву #include 1) В первом случае include по максимуму прописывают в h-файлах, но уже не пишут в cpp-файлах. Т.е. делаешь включение одного заголовочного файла, а он уже тянет все инклуды в себе. 2) Во втором случае наоборот, в h-файлах почти нет include, но все эти include спишут в cpp-файлах. При этом, если есть некие общие классы, то могут сделать так: В начале заголовочного файла ставят пустое объявление класса: class myClass;. Но этот include будет в cpp-файле. В заголовочном файле вообще нет объявления внешних типов данных. Но всё работает если в cpp-файле подключать заголовочные файлы с описанием классов перед подключением зависимых заголовочных файлов, т.е. важен порядок Вопросы у меня такие: Есть ли формальное наименование этих стилей компановки исходного кода? Как делать правильно, а как делать нельзя? Хочется изучить эту тему от и до. С чего начать?


Ответ

По моему опыту в большинстве случаев работает такой простой критерий: "минимальная" программа с любым из Ваших инклюд-файлов должна собираться. Например: // t.cpp #include "myincl1.h"
int main () { return 0; } это весь текст g++ t.cpp Компиляция должна успешно пройти. А в "myincl1.h" при этом желательно включать минимальное количество других .h файлов (как системных, так и собственных). И конечно, не забывайте писать #ifndef _MYINCL1_H #define _MYINCL1_H .... #endif // _MYINCL1_H в начале и конце своих .h Собственно, это требование к правильно написанному заголовочному файлу. Естественно, не должно быть никаких зависимостей от порядка включения файлов. Иногда для сокращения писанины удобно написать два-три "обобщающих" .h-файла, которые включают большинство собственных и системных .h, нужных для конкретной программы (используются во многих ее модулях).

Выравнивание данных

Здравствуйте! Наткнулся на термин Выравнивание данных в статье «Оптимизация кода на C++ (C++11) на примере конкретной задачи». В той статье код оптимизируется путем изменения порядка расположения переменных в структуре.
Почему происходит оптимизация кода, только из-за изменения порядка расположения переменных?


Ответ

Если честно, то просто не обращайте на это внимания. Такая нанооптимизация не понадобится большую часть вашей жизни. Большая часть проблем решается не перестановкой полей структуры, а вдумчивым переписыванием алгоритмов и выбором подходящих структур данных. Хотя конечно знать про это надо.

Итак, смотрите, в чём дело.
Память компьютера работает следующим образом. Память программы можно представить себе как большой массив байт, а адрес — индекс в этом массиве.
[байт 0] [байт 1] [байт 2] [байт 3] [байт 4] [байт 5] [байт 6] [байт 7]...
(Ну или иногда легче представлять так:
... [байт 7] [байт 6] [байт 5] [байт 4] [байт 3] [байт 2] [байт 1] [байт 0]
— вам ещё предстоит узнать про разницу между Big Endian и Little Endian.)
Байт, как минимально адресуемую единицу памяти, можно адресовать как угодно. Но обычно вы работаете с более крупными единицами. Например, это машинное слово: размер регистра процессора. Для 32-битной архитектуры это четырёхбайтовая структура.
Теперь, байты прекрасно организовываются в четвёрки:
[байт 0] [байт 1] [байт 2] [байт 3] [байт 4] [байт 5] [байт 6] [байт 7]... [ машинное слово 0 ] [ машинное слово 1 ]...
Но заметьте, что в принципе байты можно бы комбинировать в машинные слова и по-другому:
[байт 0] [байт 1] [байт 2] [байт 3] [байт 4] [байт 5] [байт 6] [байт 7] [байт 8]... [ машинное слово ] [ ещё одно машинное слово ]...
— машинное слово может начинаться по любому адресу!
Так вот, большинство компьютеров устроено так, что машинные слова, скомбинированные в четвёрки верхним образом читаются быстро, а вот машинные слова второго типа (то есть, те, которые не получаются шагами по 4 от нуля) — медленно. (Хотя требования по выравниванию могут быть и сложнее, и не совпадать с кратностью машинного слова.) Хуже того, очень многие архитектуры вовсе не позволяют читать такие слова, и для того, чтобы прочитать вот такое слово:
[байт 0] [байт 1] [байт 2] [байт 3] [байт 4] [байт 5] [байт 6] [байт 7]... [ машинное слово ]
приходится читать машинные слова по адресу 0 и 4
[байт 0] [байт 1] [байт 2] [байт 3] [байт 4] [байт 5] [байт 6] [байт 7]... [ нужно это машинное слово ] [ но приходится читать это ] [ и это ]
выбирать из них нужные байты, перетасовывать и собирать «вручную» в нужное машинное слово! Понятно, что это сложная и сравнительно дорогостоящая операция.
Поэтому компиляторы языка программирования C (да и большинства других тоже) проводят такую оптимизацию: между полями структуры вставляются незначащие байты для того, чтобы у всех полей было хорошее выравнивание.
Пример: для такой структуры:
struct { char x; // 1 байт int y; // 4 байта char z; // 1 байт };
память выделяется так:
[ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ x ] { потерянные байты } [ y ] [ z ] { потерянные байты }
Если сама структура будет выровнена в памяти (об этом компилятор тоже заботится), то y будет выровнено, и доступ к нему будет быстрым (а на некоторых платформах, напомню, вообще только в этом случае возможен).
Но в этом случае наша структура занимает больше памяти, чем если бы порядок переменных был таким:
[ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ x ] [ z ] { потеряно } [ y ]
Бóльшая структура означает бóльший расход памяти и бóльшие затраты на копирование, чтение этой структуры и тому подобное. Таким образом, переставив поля структуры, мы можем сэкономить.

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

Дополнительное чтение по теме (на английском): http://www.catb.org/esr/structure-packing/

Почему выходит -128?

Создадим переменную, увеличим на 1, выведем на печать:
byte a = 127; a++; System.out.print(a);
Почему выходит -128? Логично, что byte не может быть больше 127. Но хотелось бы точного ответа.


Ответ

В переменной типа byte содержится 8 бит. Старший (самый левый) бит отвечает за знак. Если старший бит 1, то число отрицательное, если 0 - то неотрицательное (ноль или положительное).
127 в двоичном представлении - 01111111
Если к этому числу добавить 1, то получится 10000000 (-128), то есть увеличивая число, мы "залезли" в знаковый бит и превратили число в самое маленькое отрицательное, которое может содержать тип byte