Patnáctka podruhé - úvodní přehled

Druhá verze H15 (číslovaná jako 1.1.0) je venku, tudíž opět nastal čas na resumé, co všechno se podařilo, ale tentokrát i co se nepodařilo. Původně jsem si myslel, že skládání obrázků místo čísel bude pouze triviální výměna jednoho obrázku za jiný, nakonec z toho bylo poměrně dost programování. Resumé rozdělím na tři části, bude trochu více snippetů. Začnu ale přehledem užitečných drobností.

Dieta pro obrázky

S programováním jako takovým to nemá nic společného, ale pro vývoj aplikace je to také důležité.

Když jsem připravoval fotky pro distribuci s aplikací, řešil jsem také velikost souborů s fotkami, aby velikost aplikace zbytečně nenarostla. Přitom jsem objevil zajímavou službu TinyJPG a její variantu TinyPNG - obě služby pocházejí od téhož autora. Služby dokáží zpracovat obrázky tak, aby byla zmenšena velikost souboru, ale aby obrázek jako takový zůstal zachován - včetně rozměrů. Výsledný obrázek je od originálu k nerozeznání.

Službu jsem použil na všechny obrázky v aplikaci: nejen fotky, ale i kostky s čísly, pozadí a jiné. Velikost souboru byla zmenšena na polovinu až třetinu, někdy i čtvrtinu. Obrázek s pozadím aplikace byl zmenšen z původních cca 250 kiB na výsledných cca 90 kiB. To je pořádná redukce. Doporučuji!

GUI a vlákna

Co se GUI týče, má Android také koncept jednoho vlákna: GUI události jsou zpracovávány v jednom vlákně, žádné jiné vlákno nesmí ke GUI přistupovat. Často ale přijde úloha spustit déletrvající operaci mimo GUI vlákno a po skončení ukázat výsledek v GUI. Knihovny Androidu pro tento účel obsahují třídu AsyncTask, což je docela šikovná šablona pro implementaci takovýchto úloh. Stačí implementovat pouze metodu s operací mimo GUI, pak metodu s odezvou pro GUI a případně ještě metodu pro zobrazení mezistavu v GUI. O spuštění v patřičných vláknech se AsyncTask postará sám.

To mi připomnělo, že podobný typ úloh jsem řešil v SWT. Tam ale podobná utilitka chybí, proto jsem ji musel naprogramovat sám. Snippet ale nezveřejním. Přestože se jedná o obecný princip a dobrý SWT programátor si implementaci dokáže snadno představit, přece jenom jsem to programoval pod hlavičkou Siemens. Zdrojáky bývají považovány za důvěrné materiály...

Zpracování obrázků

Při práci s obrázky jsem často narážel na OutOfMemoryError. Bylo proto zapotřebí obrázky zmenšovat. Tomu je věnována přímo jedna kapitola oficiálního Android tutoriálu. Dle internetových fór je tento postup - napřed dekódovat pouze rozměry obrázku a pak přes BitmapFactory.Options.inSampleSize určit zmenšení - považován za best practice a je často odkazován. A také bývá často odkazována implementace metody calculateInSampleSize(...) dle tutoriálu coby best practice pro výpočet zmenšení. Nebyl proto důvod vymýšlet jiné řešení.

Taktéž se osvědčíla implementace memory cache pro obrázky pomocí třídy LruCache dle tutoriálu. Implementoval jsem ji podobně. Přestože jsem k obrázkům v cache přistupoval přes jejich resource ID (R.drawable.<filename>, což je typ int), uvnitř cache jsem jako klíč použil String. To mi umožnilo rozlišit, jak je obrázek zpracován:

  • původní obrázek - kostky puzzle s čísly
  • miniatura - dialog výběru obrázků
  • kostka puzzle - obrázek po rozdělení na kostky

Zejména v případě kostky puzzle se osvědčil String jako klíč, mohl jsem tak klíčovat jak pomocí resource ID (přednahrané obrázky), tak pomocí Uri (vlastní fotka uživatele). Zdroják pro rozdělení obrázku na kostky pak mohl být jenom jeden společný pro přednahraný i vlastní obrázek.

Velikost paměti coby 1/8 dostupné paměti je dle Internetových fór běžná praxe. A protože metoda Bitmap.getByteCount() je k dispozici až od API level 12 (Android 3.1.x), implementoval jsem odhad velikosti obrázku následovně:

return bitmap.getRowBytes() * bitmap.getHeight() / 1024;

GridView vs. DialogFragment

Když jsem vytvářel dialog pro výběr obrázku, využil jsem třídu DialogFragment. Součástí dialogu byla i komponenta GridView - tabulka s obrázky. Když jsem nastavil výšku GridView způsobem android:layout_height="FILL_PARENT", výsledná velikost dialogu sice odpovídala velikosti displeje, nicméně docházelo k rozházení dialogu nebo podkladové Activity. Řešením bylo nastavit pro GridView výšku jako fixní. Pro telefony se osvědčila výška 330dp při otočení na výšku a 220dp při otočení na šířku, pro tablety se pak osvědčiluy hodnoty 600dp při otočení na výšku a 400dp při otočení na šířku.

Animovaný placeholder při načítání obrázků

Na závěr věc, která se nepovedla. Protože v dialogu pro výběr obrázku načítám obrázky podle potřeby mimo GUI vlákno, zobrazuji misto nenačtených obrázků placeholder - obrázek signalizující, že se vlastní obrázek teprve načítá. Se statickým obrázkem nebyl problém. Horší však bylo, když jsem chtěl obrázky nahradit animacemi - střídáním několika obrázků. Výledná animace však byla pomalá, trhaná, nespolehlivá a tudíž nepoužitelná. Proto jsem se rozhodl od záměru animovaného placeholderu ustoupit.

Tagy: H15, Android, Java, Programování

Tento web bude tebe a tvůj počítač krmit piškotkami, jelikož a protože je to slušný web a jako takový ví, že je potřeba návštěvu řádně pohostit, aby se u nás cítila dobře. Užíváním tohoto webu potvrzuješ, že netrpíš mentální anorexií, nedržíš žádnou obskurní dietu a že můžeš piškotki do sebe cpát kdykoli a v jakémkoli množství. Více informací...