софтуер


Project weather station 1

IMG_2466-2

Описаното тук устройство е от тип „домашна метео-станция“.

Използваният хардуер на устройството е следният:
Waveshare 4.3 e-ink екран
Arduino Uno
Adafruit BME280 комбиниран сензор за температура, налягане и влажност на въздуха
DS3231 базиран хардуерен часовник

Функционалност

  • час
  • дата
  • температура
  • налягане
  • относително налягане
  • влажност
  • краткосрочна прогноза
  • тенденция на налягането

Основните предизвикателства при разработката бяха:

  • използване на шрифт, различен от вградения във firmware-а на дисплея
  • създаване на изображения при ограниченията на паметта на използвания микроконтролер
  • избора и имплементацията на алгоритъм за прогноза

Шрифт
Дисплеят разполага с вграден набор от шрифтове, които са растерни, съдържат само латински и китайски символи и са с три размера. За съжаление шрифтовете са различни за различните размери, което представлява проблем за създаването на удобен и естетически издържан интерфейс на устройството. Решението беше да се дефинира статично в кода (като тримерен масив) шрифт със символите за цифри, всеки от които се състои от 5×7 пиксела. Първоначално беше използван един байт за всеки писел, но поради ограничената RAM памет на микроконтролера това заемаше почти цялата налична памет. Решението на това беше да се използва един байт за всеки стълб от изображението на символа, което води до загуба само от един бит на всеки 7.
Библиотеката с API функциите на дисплея съдържа примитиви за чертане на запълнена окръжност, която използвах за изобразяване на символите. Създадената от мен функция получава като параметър размера на шрифта, което определя диаметъра на окръжността и разстоянието между отделните окръжности и в резултат получих шрифт с променлив размер, неограничен от фиксираните три размера на вградените в устройството шрифтове.

Изображения – икони за прогноза
Дисплеят поддържа качването на изображения във вградената памет, но те са растерни и не подлежат на мащабиране. Поради това реших да създам програмни функции за изчертаване на икони, базирани на наличните графични примитиви, които както и при шрифтовете да дадат възможност за промяна на размера. Изображенията, на които се спрях са за слънце, облак и дъжд, които могат да се комбинират по различни начини. Бяха използвани примитивите за запълнена окръжност и правоъгълник, за да се създадат стилизирани контурни изображения. За съжаление обаче API на дисплея не предоставя функция за линия, на която да се определя дебелината. Това наложи имплементацията на базовия алгоритъм на Bresenham, като вместо пиксели се чертаят окръжности, което определя дебелината на линията.

Алгоритъм за прогноза
Извършеното от мен проучване показа, че производителите на съществуващите устройства от този тип не публикуват никаква информация за използвания от тях алгоритъм за определяне на краткосрочната прогноза на времето. В публично достъпната част на Интернет единственият описан алгоритъм за тази цел е т. нар. Zambretti алгоритъм, кръстен на двамата си създатели Negretti и Zambra и създаден през далечната 1915-а година. Входните данни са сезон, относително налягане, тенденция на налягането (покачване, падане или стабилно), земно полукълбо и посока на вятъра. Алгоритъмът е емпиричен и създаден за северното полукълбо и по-точно Великобритания. Извършени анализи показват, че посоката на вятъра има ограничен ефект върху крайния резултат, което улеснява прилагането му. Температурата, влажността и абсолютното налягане се връщат от използвания сензор, но относителното налягане трябва да бъде изчислено. Съществуват различни формули за това, като използваната от мен е следната:

Screenshot from 2017-09-14 17:33:12

където
P0 е налягането на морското равнище
P е измереното налягане в хектопаскали
h е надморската височина в метри
T е температурата в градуси по Целзий.

Проблем представлява определянето на надморската височина. Използваният от мен сензор връща приблизителната височина, но тъй като е базиран на барометричното измерване се влияе от него. Експериментите установиха, че при промяна на налягането, което всъщност е най-важния индикатор за промяна на времето се променя и изчислената надморска височина, което води до „закотвяне“ на изчисленото относителното налягане и в резултат на това до неточни прогнози. За решаването на този проблем може да се подходи по два начина – да се събират данни за налягането за продължителен период от време и да се вземе осреднена стойност или да се въвежда ръчно от потребителя. И двата подхода имат своите ограничения – първият изисква продължително събиране на данни и памет за съхранението им, а вторият изисква от потребителя да знае точната надморска височина. Това обаче е цената за получаване на адекватна краткосрочна прогноза.
Предизвикателство се оказа и определянето на тенденцията, защото всички материали по темата просто казват, че възможните стойности са „покачване“, „понижение“ и „стабилно/без промяна“, но не дефинират тези понятия. В публикации, несвързани с конкретния алгоритъм тези понятия са дефинирани като промяната на налягането в хектопаскали с една или повече единици за между един и три часа. Поради това се спрях на следната реализация: съхранявам стойностите на относителното налягане на всеки 10 минути в масив от 10 елемента. Когато масивът се запълни тенденцията се изчислява като разликата между средните на първите три и на последните три стойности. Масивът се използва като опашка, като единадесетата постъпила стойност отива на десето място, а първата се премахва и т. н.

Алгоритъмът на Zambretti на базата на входните параметри връща число, което се сверява с таблица от текстови описания на прогнозата. Някои от компютърните реализации на алгоритъма се стремят да изведат формула между числото и съответните стойности, но поради ограничената поддръжка на реални стойности в микроконтролера използвах подхода, избран от разработчиците на популярната Javascript имплементация на алгоритъма и използвам числови интервали, определени от условни оператори в кода.

Таблица със съответствията между текстовите описания на алгоритъма на Zambretti и използваните изображения

Понижение на налягането
Settled fine
Слънце
Fine weather
Слънце
Fine becoming less settled
Слънце, облак
Fairly fine showery later
Слънце, облак
Showery becoming more unserttled
Облак
Unsettled, rain later
Слънце, облак, дъжд
Rain at times, worse later
Слънце, облак, дъжд
Rain at times, becoming very unsettled
Облак, дъжд
Very unsettled, rain
Облак, дъжд

Стабилно налягане
Settled fine
Слънце
Fine weather
Слънце
Fine possibly showers
Слънце, облак
Fairly fine showery later
Слънце, облак
Showery bright intervals
Слънце, облак, дъжд
Changeable, some rain
Слънце, облак, дъжд
Unsettled, rain at times
Облак, дъжд
Very unsettled, rain
Облак, дъжд
Very unsettled, rain
Облак, дъжд
Stormy, much rain
Облак, дъжд

Покачване на налягането
Settled fine
Слънце
Fine weather
Слънце
Becoming fine
Слънце, облак
fairly fine, improving
Слънце, облак
fairly fine, possibly showers
Облак
showery early, improving
Облак, дъжд
Changeable mending
Облак
rather unsettled Clearing later
Облак
unsettled, probably improving
Облак
unsettled, short fine intervals
Облак
Very unsettled, finer at times
Облак, дъжд
Stormy, possibly improving
Облак, дъжд
Stormy, much rain
Облак, дъжд

Бъдещо развитие
определяне на фазата на Луната
показване на деня от седмицата
добавяне на бутони за настройка
добавяне на енерго-независима памет за съхранение на събраните данни
външен сензор за температура и влажност
добавяне на изображение за буря
свързване през WiFi към мобилни устройства за настройка и управление
показване на събития – рождени и именни дни, официални празници и лични ангажименти, дефинирани от мобилно приложение

Download:

Можете да го изтеглите оттук:

https://github.com/fandonov/weatherstation

Връзки
https://www.apple.com/shop/accessories/all-accessories/homekit?page=1
http://keisan.casio.com/exec/system/1224575267#!


Създаване на pdf от множество картинки под Linux

convert *.jpg my_new.pdf
Ако изображенията съдържат интервал трябва да е
convert “*.jpg” my_new.pdf
Страниците се подреждат според имената на файловете, така че имайте предвид следното:
page10 е преди page1, ако искате да са в правилната последователност трябва да сте ги кръстили page01 и page10


Следене през гърсене на wi-fi

Никога нямаше да ми хрумне, че могат да те следят и така. Отчасти разбира се, защото не познавам детайлите на протокола, но и да ги знаех сигурно пак нямаше да се сетя. Много голям зор явно е да се следят хората непрекъснато. А, и браво на Apple че го оправят в iOS 8, но за съжаление това не решава проблемите с privacy-то в iDevice-ите.

http://arstechnica.com/apple/2014/06/ios8-to-stymie-trackers-and-marketers-with-mac-address-randomization/


Недоволни (l)user-и

Първият ми Android app – Health Calc вече е на почти година. За това време пуснах безчет версии и нови функционалности, имах растежи и падения и към момента имам 21 000 активни потребители. Искам обаче да споделя, да се възмутя и огорча от тези, които не са доволни от него. Отначало беше със супер висок рейтинг – ясно, свалят го мои познати и техни познати и никой няма да даде малък рейтинг. С времето разбира се това се променя. Почват да го свалят хора, които не си представяш че могат да съществуват от места, които не би намерил и на картата. Между другото тук има и морал – ако се опитваш да cheat-ваш системата като врънкаш всеки познат да го тегли и да му дава 5 звезди можеш само донякъде. Но ако наистина стане популярно, което е целта на всеки разработчик, то в един момент този инструмент изгубва смисъл. Както и платените писачи на положителни коментари, които ме заливат с оферти между другото. Така че на лъжата краката са къси. Докато приложението беше по-апокрифно рейтингът беше много висок – по-висок от този на скайп 🙂 Напоследък обаче пак дръпнах в класацията на health and fitness категорията – в България държа стабилното второ място и в този момент рейтингът тръгна надолу. Отначало си помислих, че има някакъв бъг, но не бях обновявах версия наскоро, така че промяна в тенденцията нямаше логика. Получих един смислен feedback от една англичанка и оправих проблем с конкретна версия на андроид (защото шибаният numberpicker изглежда и работи коренно различни във версии 3 до 4.03 и от 4.1 до 4.4, което не е документирано). Повечето слаби рейтинги обаче са без никакъв коментар. И оставаш в чуденка какво не им е харесало – интерфейса, формулите, съдържанието, превода, дали е гръмнало или нещо друго е работело некоректно. Положителните също не са подробни в това, което им харесва – обикновено са “супер”, “много добро” и т.н., но отрицателните държат рекорда по необоснованост. Тук-там на 20 отрицателни има по един, който казва “идеалното тегло е за анорексици”, което е най-подробното и конкретно нещо получавано за обратна връзка, но преобладаващите от тези с коментар са “нищо вярно”, “далече от истината”. Култов отрицателен коментар и личен любим е “тъпо! Няма нищо, което да не зная”. В app-а се изчислява:
* BMI (Индекс на телесна маса)
* WHtR (Отношение Талия-Тегло)
* Метаболитен индекс
* Максимален дневен прием на въглехидрати, белтъци и мазнини според ниско-въглехидратната диета (НВД), кетогенната диета, диета на Аткинс, зонова диета, диета с малко мазнини и др.
* Желани нива на пулс при трениране
* Идеално тегло
* Максимална дневна доза кофеин
* Препоръчителна дневна доза витамини и минерали
* идеална талия

Тенденция, която забелязах със задоволство е, че особено при жените, тези които дават висок рейтинг имат снимки и изглеждат добре. Тези, които дават нисък рейтинг нямат снимки. :-D. Изводите от това не са еднозначни, но е забавно.
Та според мен е много тъпо да дадеш рейтинг една от пет звезди и да не напишеш какво според теб не е наред. И при научните рецензии най-трудно се пишат отрицателните, обосновката е по-дълга и по-трудна.
Затова смятам, че в Интернет не трябва да се допускат необосновани отрицателни рейтинги. Или каквито и да е всъщност. Смисълът на рейтингите е дадат информация на бъдещите потребители, за да знаят дали да изтеглят и ползват даден апп или продукт или услуга или нещо. В Deal Extreme са решили проблема като оставянето на рейтинг е обвързано с попълването на полета за положителни и отрицателни страни плюс рейтинг с коментар по категории – опаковка, дизайн, функционалност и т.н. Така много малко хора пишат, но няколкото коментара давят ясна картина за продукта. В настоящия вариант в който имаш – средно 3.9, 250 човека са дали 5 звезди, 50 са дали 1 звезда нищо не се разбира. В крайна сметка ако коментара не струва твои пет минути да го напишеш, сигурно не струва на бъдещите потребители едната минута за четене. Не вярвам Гугъл да го въведат някога, но все пак мисля, че настоящата система в крайна сметка не прави добре това, което е нейна цел – да дава информация за продукта от негови потребители за бъдещи такива.


Android rant #4

Пускането на бета версия в google play е усилие, еквивалентно на писането на app-а. Супер НЕ-очевидно е че трябва да “публикуваш” в бета, не просто да качиш APK-то, че трябва listing-а в app store-а да е направен изцяло, и накрая за капак, след като си направил гугъл плюс група, поканил тестъри, качил бета, публикувал бетата, чакал да стане активен линка, разпратил линка на участниците в гугъл плюс групата се оказва, че се очаква тези въпросни бета тестери ДА СИ ПЛАТЯТ ШИБАНОТО ПРИЛОЖЕНИЕ! При условие, че Licensing ала-балата работи само за платени приложения, а цената на едно платено приложение не може да е по-малка от 0.99 цента, как мога да тествам платено приложение заедно с проверка на лиценза, без да карам тестърите да платят цената? Мога да им пратя ръчно APK-то и да ги бутам един по един мейлите в списъка с тестъри в google play developer console, но това обезмисля наличието на beta в google play.
Допълнение: Това е добро описание на процеса на публикуване на бета


Android rant #3

В един от app-овете имам падащ списък, който Гугъл са кръстили spinner?!? Записвам стойността, посочена от потребителя чрез този падащ списък и искам при отваряне на приложението да заредя стойността и да я задам на падащия списък. Изглежда нещо, което отнема 5 секунди, нали?
Първо трябваше да загубя три минути докато налучкам името на метода – setSelection. Окей, значи извикваме този метод с параметър поредния номер на стойността, която искаме да установим, нали?
sb.setSelection(w);
Да, само че нищо не става. След дебъгване и уверяване, че проблемът не е в мен, тръгвам да търся решение из форумите.
Ами, първо, трябвало да се зададе true на незадължителния втори параметър animate.
Супер, значи кодът става
sb.setSelection(w,true);
Пак не работи. Трябвало тоя метод да се вика само след като вече е извикан setAdapter. Вярно, има логика първо да напълниш падащия списък със съдържание, после да му избираш кой от елементите да показва.
Значи кодът с преместения от по-долу става:
ArrayAdapter dataAdapter2 = new ArrayAdapter(this,
android.R.layout.simple_spinner_item, list2);
dataAdapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sb2.setAdapter(dataAdapter2);
sb.setSelection(w,true);

Ииии имаме ефект, но частичен. Тъй като всъщност имам два spinner-а, вторият получава записаната стойност. Но не и първият? Кодът за всичко е супер аналогичен. Какво правим?
Ами всъщност, то ако се опитваш да изпълниш това на onCreate на активитито, то още не било завършено създаването му, а пък ние пипаме нещо по визуалните компоненти, които съдържа, и не можело. И затова трябвало да се отложи това задаване на стойност за след като се създаде activity-то изцяло.
Пишем значи нещо от типа на:
sb.post(new Runnable() {
public void run() {
sb.setSelection(w);
}
});

И не може, защото тоя Runnable е анонимен вътрешен клас и няма достъп до атрибутите от външния клас, ако тия атрибути не са final(което е ясно защо). Добре, значи теглим една майна на всичко, замижаваме за лошия стил искайки само да подкараме шибаното нещо да тръгне правим тези стойности атрибути на activity-то, и правим get метод, та да може да се обърнем към него от вътрешния клас.

sb.post(new Runnable() {
public void run() {
sb.setSelection(getW());
}
});

И цялата тая одисея за нещо, което на разни други езици би работило от първия опит, демек само обръщение към setSelection с параметър индекса на елемента, който да бъде зададен. Ама не, би било много лесно. Затова четене, пробване на някакви решения, дето по документацията никакви ги няма и загуба на половин час от живота ми, който е тотално пропилян, защото на разни други езици и среди това се прави за 5 секунди. От 1994 година насам…
Но мобилното не е същото като десктоп и затова ще чакаме 3000 година Гугъл да направи скапания Андроид и писането за него нещо подобно на Visual Studio, Delphi или HTML5/JS или дори Qt. Не случайно списъкът е разнороден, писането не е удобно нито като език, нито като среда.


Млади меринджеи

Disclaimer: Тук е изложено лично моето мнение, като описаната дискусия беше повод, а не причина да напиша тези неща, които си ги мисля отдавна за ИТ(а и не само) бизнеса в България
Вчера бях поканен на кръгла маса, на която се дискутираха кадрите в един конкретен IT сектор. За съжаление аз бях единственият представител на образователна институция, имаше двама от бизнеса, един от общината и един от пазара на труда. Казаха се някои много интересни и верни неща, което ме изненада приятно – очаквах такова официално нещо да е на доста по-политически език – много говорене и не казване на нищо. Любопитно беше изказаното твърдение, че високото заплащане е резултат на огромната дупка в предлагането на пазара на IT труд и че ако се насити пазара заплатите в сектора ще паднат до тези на другите професии. Хубаво беше, че се каза и за това, колко неподготвени, а със самочувствие и без желание “да копат” са някои млади хора. И там стигнахме до това какво е обучение. И как бизнесът с огромно, ама ОГРОМНО нежелание инвестира в обучение на персонала и как “в идеалният случай новите кадри при постъпване ще имат нужда от нула обучение.” Сядат и почват да кодят. Аз се опитах да вметна, че това е краткосрочно, че трябват И фундаментални знания, за да може да са гъвкави тези хора и при промяна на технологиите тези хора да могат да се преквалифицират бързо. Дадох пример от дотКом(как се пише това на български?) бума, как американските университети са подготвяли тясно специализирани кадри без много фундаментални знания и след пукането на балона хиляди хора са останали без работа и шанс за работа, защото техните знания са безполезни, а те нямат фундамента за да се преквалифицират. И че тогава самият американски IT бизнес отишъл при университетите и казал – абе я обучавайте с по-широка основа, за да са ни по-универсални и гъвкави специалистите. Казах тези неща и видях бърчене на устни и неварбилизирано неодобрение. Защо според мен тази позиция на бизнеса не е правилна?
Въпросът, както изобщо с бизнеса, е дали се гледа краткосрочно или дългосрочно. Американският модел всяка година ни доказва, че е на принципа “максимизирай печалбите в края на тази година, дори с цената на фалит догодина”. Ако IT бизнесът гони бързата печалба и не се интересува да направи своя дял от работата за подобряване на климата в тази сфера, то тогава в цитирания по-горе идеален за бизнеса вариант университетите ще подготвят кадри, които са супер тясно специализирани в най-модерни към даден момент технологии и фирмите няма да влагат стотинка в обучение при назначаване на нов човек. Но разбира се безплатен обяд няма, както обича да казва бизнеса, но винаги в контекст, че той трябва да получи пари, а не да даде. Защото когато тези умения остареят, наетите хора с много конкретни умения ще бъдат излишни. Бизнесът просто ще получи следващата порция млади IT специалисти от университетите, а тези ще изхвърли. За бизнеса изглежда няма нищо лошо. Но бизнесът не е единствената страна тук. Защото уволнените ще имат сериозни проблеми да си намерят работа. Заради високите заплати вече ще са се увътрили с някой кредит за 100 000 и седейки без работа ще затъват много много бързо. Държавата ще отчита безработица, ще плаща някакви пари, макар и минимални. Университетите на разни акредитации ще им се пише, че от тяхната продукция от висшисти еди колко си процента са безработни или не работят по специалността. Тези които си намерят някаква по-ниско квалифицирана работа ще подбиват парите в сектора. Което в още по-дългосрочен аспект ще означава че по-малко млади хора ще намират IT индустрията за привлекателна. А на врата на държавата ще висят хиляди хора с много претенции и малък шанс за реализация, които имат още половин век до пенсия. Това за мен не е добър бизнес климат. Но максимизира непосредствената печалба, защото те няма да обучават.
Какво според мен е по-правилна стратегия?
Да се мисли стратегически, а не тактически. Важно е бизнесът да оцелее догодина, но всъщност не е важно шефът да си купи новото ламборджини в края на годината. В обучението е по-добре да има баланс между фундаментални предмети и конкретни занаятчийски предмети. Тук баланс е ключовата дума.
Прекалено много от първото и се получава програмата на държавен университет от преди 15 години -супер много математика, асемблери, фортрани, бейсици и нищо модерно. Успешно завършилите са умни и гледат на програмирането като на логическа задача, но или не знаят нищо за използваните от бизнеса технологии или са си го учили сами.
Прекалено много от второто и получаваме хора, които знаят новите технологии, но не и как работят. Образно казано са като секретарките, които са научили Word 2013 и знаят, че за да “сейвнат” файла трябва да щракнат на червеното дискче. Когато в Word 2014 save е изнесен на лентата с бутони с икона на синьо блу-рей дискче те не могат вече да го ползват. Имат нужда от преквалификация. Тоест хора, които от първия ден на работа дърпат клавиатурата и почват да тракат, при първата по-голяма промяна отиват на опашката за помощи.
Балансът за мен означава на студентите да се даде фундамента от знания, който наистина ги прави специалисти плюс няколко основни технологии, които се ползват в момента. Но именно в IT сферата нещата са супер динамични. Нещо, което днес е върха на сладоледа след 5 години е остаряло и мухлясало. Ако искаме специалисти, които да работят в избраната от тях област през целия си живот, а не само първите пет години след завършване, трябва бизнесът да поеме своя дял и периодично да обучава хората си на новите технологии. Пари са, да, но това се нарича инвестиция. За да вземеш, трябва и да дадеш.
За да обобщим (малко цинично), от предишни срещи съм забелязал, че бизнесът разбира demand and supply така: I demand and you supply. Те буквално казват – дайте ни кадри, които могат да пишат на български, да знаят английски, да имат “меки умения”, да имат фундамент и да знаят всички най-нови технологии. И ако сте ги научили и да не ядат и да не искат пари ще е супер. Това в краткосрочен аспект е изгодно, но бизнес средата няма да е много хубава, защото ще й липсва човешкия капитал. А по меринджейските книги пише, че той бил най-важният. 😉 Циничният бизнес може да казва – не искам да давам стотинка за обучение на персонала ако университетите могат да ги обучат на всичко. Но един частен университет може цинично да каже – да, но нашите клиенти са студентите. Ако ги наемате обучени и така, донякъде, без да знаят всички най-нови технолгии, защо да даваме повече пари за да ги учим и на още неща. Докато ги обучаваме достатъчно добре, за да могат да си намерят някаква работа и да мотивират следващия випуск да запише пак при нас, другото не ни интересува. И затова трябва да има “някаква” регулация (току-що описаната картинка всъщност прилича много на tragedy of the commons). Защото краткосрочните цели и на университетите и на бизнеса и на самите студенти-след-това-работещи всъщност са в противоречие с дългосрочните. И ако искаме IT бизнес и експертни кадри в него и след 20, 30, 50 години, трябва да си сложим и очилата за “дълго гледане”.

P.S. Допълнителен въпрос за домашна работа: Ако в IT сферата младите технически кадри са с неоснователно високо самочувствие, което няма покритие със знания и умения, какви са младите HR и меринджейски кадри в IT сферата?

P.P.S. Разбира се не успях да кажа всичко това, трябваше да приключваме и всички избягаха на следващия event – някакво представяне на две от много големите фирми в този сектор. Остана един студент. Заприказвахме се и той ми разказа как точно тези две големи фирми са го прецакали. На едната им напуснал някакъв специалист в критичен момент. Отворили позиция, на интервюта минали над сто човека, не наели никого а в крайния продукт се появили проектите, които са правили за интервюто…


Android rant #2 – RatingBar

В едно приложение ми се налага да показвам графично изчислен score от някаква формула. Тъй като оценката е тип колкото по-голяма стойност толкова по-хубаво, ми се стори добра идея да показвам резултата като звездички. Сетих се, че съм виждал в палитрата такъв компонент и го намерих – ratingbar. Стори ми се точно каквото търся. Има звездички, които са или пълни или празни, въбще нещо като ProgressBar, но с custom фон. Има свойства за гранулярност, за максимален брой звездички, за текуща стойност и т.н. Когато обаче го пуснах в емулатора на portrait ориентация на телефон се оказа, че се виждат само 3-4 звездички. Затова намерих някакъв tutorial и сложих custom изображения за пълна и празна звездичка, които да са значително по-малки. И се оказа, че всъщност както и да го въртиш, ProgressBar-ът показва толкова звездички колкото може да разположи на наличното пространство. Всъщност изглежда принципът е, че поставя първо празните звездички колкото пъти се събират (включително може да са отрязани, което е грозно само по себе си), после поставя отгоре изображение с пълните колкото пъти се събират. Тоест две съставни изображения от повтарящ се мотив се монтират едно върху друго, като горното е толкова широко, колкото е зададената стойност съотнесена към физическият размер. Така се получават частите от цяла стойност. Но в резултат изобщо не може да се гарантира точният брой звездички, които се показват. Ако искате да покажете стойност 5 от максимално 10 звезди, а на екрана се събират само 6, ще бъдат запълнени 3. Което явно им се е сторило много хитро, но всъщност не е. Защото по този начин променяме базата. Едно е 5/10, друго е 1.5/3. Представете си ако приложението на imdb беше направено по този начин, ако го отворите в portrait ориентация на телефон ще трябва да оценявате филмите максимум от 4 звезди, въпреки че тяхната база е x/10. Така че не открих хубав начин да се оправя и за да имам гарантирани точно 10 звезди показани, ще трябва да направя примерно 30 изображения с всички възможни комбинации с точност до 0.3 и просто да сменям съответното изображение. Дървено, но по-добре работещо от направеното от Google. Защо някои са писали blog постове, в които възхвалят този компонент е beyond me, наистина.
Edit: Ето добро описание с картинки на проблема: http://stackoverflow.com/questions/12454644/android-ratingbar-a-complete-mess?rq=1


Android rant

Вчера за един ден успях да се натъкна на три бъга в Андроид, от които два са супер сериозни и неоправени, третият е просто демонстрация за мърлявщината на създателите на Андроид.
Бъг 1
Най-най-най елементарният компонент във всяка библиотека и среда за визуални компоненти е етикетът (label). Това е статичен текст, който не се редактира от потребителя и единствената му функция е да бъде текст на екрана. Тези етикети във всички езици, които съм виждал са обекти, каквито са и всички останали компоненти. Обектите имат свойства като размер, цвят, позиция и т.н. и напълно очаквано едно от свойствата на етикетите да бъде шрифтът на текста. Тук трябва да отворим една скоба и да кажем, че в Андроид създаването на интерфейса става по един от два начина. Единият е от програмният текст, другият е чрез описание в XML файл. Това също е проблем, защото двата метода за създаване на интерфейса не са напълно заменяеми. Има неща които могат да бъдат направени само от кода. И се получава много неприятно, когато си започнал с XML и на 25 компонент разбираш, че нещо можеш да го направиш, само ако го създаваш този компонент в кода. Та един такъв статичен компонент като етикета, който не връща обратна връзка от потребителя, е напълно логично да се създава от XML и там да са описани всички свойства, нали? Е да, ама не. Шрифтът на етикета може да се определи само програмно, с няколко реда малоумен текст от типа на:
Typeface font = Typeface.createFromAsset(getAssets(), "robotolight.ttf");
txt.setTypeface(font);

Но това не е причината за възмущението ми, неее. Това, че ако имаш 20 етикета трябва 20 пъти да настройваш шрифта на всеки от тях програмно е горчив, но преглъщаем хап. Това, което ми дойде в повече е когато създадох ListView от 25 елемента, установявайки шрифта на елементите в списъка на определения от дизайнерката и забелязах, че като го скролирам нагоре-надолу (пак повтарям, списъкът е от 25 статични елемента), при всяко превъртане на списъка заеманата памет се увеличава с 50 MB! След кратко четене установих, че това е известен бъг, който Гугъл очевидно не са си направили труда да поправят. Всеки път като установявате шрифта с горния текст се заделя отново памет за Typeface-а или там нещо друго и така ако имаш 8 бутона и 25 етикета в списък ще заделиш тая памет 33 пъти. И приложението ти почва да заема памет като че ще изстрелва ракети в космоса. (N.B. Това всъщност е невярно сравнение. Хората са изстрелвали ракети в космоса с изчислителна мощ колкото електронен ръчен часовник. Не смартфон. Не тъп телефон. Не калкулатор. Електронен часовник!!!) Всъщност имало някакъв много завъртян начин да установяваш шрифта на компонентите и от XML, но той не е препоръчителен, тъй като тогава със сигурност за всеки компонент ще се заделя тази памет и програмистът няма контрол върху процеса. Известен бъг, за който от Гугъл са си го преместили от левия в десния…
Вторият МЕГА БРУТАЛЕН бъг, който е СУПЕР известен, е свързан с изображенията. Сега тук забавното започва с това, че в Java приложението казва на виртуалната машина предварително колко памет максимално ще заеме. Но в Андроид тези стойности (на heap-а) са установени от Гугъл и/или от разработчиците на съответното устройство и не може да бъде променян без да си прекомпилираш андроид-а или да си root-неш телефона (Cyanogen позволявал потребителя да задава отделна стойност на heap-а на всяко приложение, уау, бахти гъзарията!). И размерите на heap-а не са никак големи, меко казано. Стойностите са определяни предимно на база размера на екрана (което най-вероятно е свързано със самия бъг, за който става въпрос), като на най-малките устройства тази памет е само 16 MB! При условие, че не съм чувал за устройство с Андроид с по-малко от 256 MB RAM и повечето са с 512, 768, 1024 и вече има и с 2048. Максималната стойност, установявана е 64 MB, което е предимно на таблети. (Samsung Galaxy Tab 2 e с heap 48 MB). Защо са такива малки размерите на heap-а ли? Ами обясненията са, че:
А. Като ти дадат повече памет, използваш повече памет! А като използваш повече памет, Garbage collector-а работи повече по освобождаването й. И тъй като garbage collector-ът не е най-ефективното нещо на света, то по-добре малко памет. Така де, по-добре да се гърчат милионите разработчици на андроид, отколкото петимата капута, които работят в Гугъл и пишат GC-то на андроид, нали? (Не твърдя, че това е официалната позиция на Гугъл за размерите на heap-а, но е аргумент, използван из форумите)
Б. Защото гениалният Андроид по принцип е направен така, че спирането на приложението е трудно. Андроид не иска да спираш приложения. Той иска само да ги пращаш назад в стека, във фонов режим, дори когато нямаш намерение да ги ползваш следващата година. И защото това пълни паметта с много работещи едновременно приложения, нека им дадем малко количество максимално допустима памет. Така де, вместо да имаме три активни приложения, които могат да работят като хората, нека имаме 30, от които 29 всъщност не се използват в момента, но заради лукса да ги имаме някъде там отдолу в стека, 30-тото приложение, което е на фокус и потребителят ползва в момента ще се гърчи, защото трябва да се ограничава от използването на RAM! Не е ли гениално?
И сега идва интересната част. Във вашето приложение искате да сложите картинки? Чудесно, поставяте ги като ресурси в проекта и си ги четете от там. Но независимо какъв тип са (jpg, png, и т.н.) веднъж заредени, андроид ги обръща в bitmap, и ги зарежда в паметта. В heap-а. Некомпресирани. И така, ако имате изображение 300×300, с 24 бита за цвят, то от паметта за приложението ви са изядени малко повече от 2 MB. А, и тъй като не вие заделяте паметта (все пак java е автоматично управление на паметта), то не можете да я освободите. Поне не директно. Тоест всяко изображение, заредено на което е да е място във вашето приложение седи в ограничената heap памет, независимо дали ползвате това изображение или не. И ако имате много изображения, много бързо изяждате тази силно ограничена памет, отредена на вашето приложение. А като се препълни паметта, приложението гърми с out of memory error. Ако не ми вярвате колко сериозен е проблемът, просто напишете out of memory error android в Гугъл и ще видите, че на първата страница почти всички сайтове коментират именно изображенията. Дефинитивно решение на проблема няма. Препоръчва се да се използват по-малки като размер изображения (компресията на jpg или png няма значение, само размерът), както и ако има възможност след използването на изображение да се извиква .recycle() , или .recycle() да се допълни с
BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

или някакви други врътки.

Можете да направите и като мен – да разберете колко е наличната памет със следния код:
ActivityManager activityManager = (ActivityManager) this.getSystemService( ACTIVITY_SERVICE );
mem=activityManager.getMemoryClass();

и после на разни места да зареждате различни изображения или различни layout-и в зависимост от размера на heap-а:

if (heap>20){
resourceId = res.getIdentifier(recipePicsBig[position], "drawable", "com.xxxxxxx");
holder.recipeImage.setImageResource(resourceId);

или
super.onCreate(savedInstanceState);
extras = getIntent().getExtras();
int heap=extras.getInt("heapSize");
if (heap>20)
this.setContentView(R.layout.single_list_item_view);
else
this.setContentView(R.layout.simple_single_list_item_view);

В обобщение Андроид заема памет за изображенията колкото е некомпресираният им размер и не я освобождава, а програмистът трябва да прави някакви фокуси, за да го излъже да освободи тази памет. Или за по-просто да не ползва изображения, очевидно в 21 век и 8 ядрените телефони според Гугъл те са скъп лукс.
Третият бъг (вече оправен), открих докато четях за управлението на паметта в Андроид и техниките за дебъгване на използваната памет. Един пич е открил, че в gmail приложението се създават няколко стотин!!! празни правоъгълника, които са с нулеви размери. Не заемат много памет, но все пак са стотици. И очевидно не се ползват за нищо, няма и как, защото са с нулеви размери. След публикуването на откритието си, около два часа след това, от Гугъл оправят нещата, но все пак това е седяло (най-вероятно) с години. В андроидско приложение, написано от хората, които притежават и разработват андроид!
И така, в обобщение, за да направя нещо толкова елементарно като скролируем списък с 25 елемента с малка картинка и текст до нея трябва да създам нов клас и да разширявам стандартния скролируем списък, тъй като той не поддържа изображения, този списък не може да има custom шрифт, защото това ще яде паметта като тасманийски дявол, и на всичкото отгоре изображенията в него ще изяждат още повече памет, като няма достъпен начин за освобождаване на паметта от непоказаните в даден момент изображения или нещо такова.