Vytváření uživatelského rozhraní (UI) v Androidu je většinou doporučováno pomocí XML, přičemž samotné uživatelské rozhraní by mělo být co nejvíce oddělené od logiky aplikace. Nicméně existují případy, kdy je potřeba upravit nabídky nebo jejich položky přímo v kódu. Tento přístup je nezbytný například v situacích, kdy se viditelnost nebo aktivita položky nabídky mění na základě vnějších podmínek, například když je uživatel přihlášen do aplikace nebo ne.

V tomto případě se zaměříme na to, jak dynamicky měnit obsah nabídky přímo v kódu. Tento přístup může být užitečný například při implementaci funkcí, které mají být k dispozici pouze pro určitý typ uživatele nebo za určitých podmínek. Pro tento účel není nutné vytvářet samostatné soubory XML pro každou variantu nabídky, místo toho budeme vše provádět pomocí kódu v jazyce Java.

Začneme tím, že si vytvoříme nový projekt v Android Studiu s názvem RuntimeMenu. Bude obsahovat prázdnou aktivitu a budeme pracovat pouze s kódem. K tomu nebude nutné vytvářet adresář res/menu, protože menu vytvoříme a upravíme výhradně v kódu.

Prvním krokem je přidání řetězcových zdrojů pro položky menu a tlačítka pro přepínání viditelnosti menu. V souboru res/strings.xml přidáme potřebné položky pro "Download" a "Settings". Dále v souboru activity_main.xml přidáme tlačítko, které bude volat metodu toggleMenu.

Ve třídě ActivityMain.java přidáme několik řádků kódu pro definování identifikátorů pro jednotlivé položky nabídky a booleovské proměnné pro sledování stavu zobrazení položky nabídky. U tlačítka přidáme metodu toggleMenu(View view), která bude přepínat stav viditelnosti položky.

K vytvoření nabídky v metodě onCreateOptionsMenu(Menu menu) použijeme metodu menu.add(), kde přidáme položky menu a přiřadíme jim identifikátory, které jsme definovali dříve. Poté použijeme metodu onPrepareOptionsMenu(Menu menu), abychom dynamicky upravili viditelnost položek podle aktuálního stavu aplikace.

Důležité je, že změny v nabídce by měly být prováděny v metodě onPrepareOptionsMenu(), protože tato metoda je volána při každém zobrazení nabídky, což nám umožňuje změnit obsah nabídky na základě aktuálního stavu aplikace. Pro zajištění správného chování je doporučeno volat metodu invalidateOptionsMenu() v situacích, kdy dojde ke změně stavu aplikace, která ovlivní nabídku.

Další zajímavou funkcí je možnost zobrazení položek nabídky v Akční liště. K tomu stačí přidat řádek kódu menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS), což způsobí, že daná položka bude vždy viditelná v akční liště. Pro správné chování je opět důležité volat invalidateOptionsMenu(), aby se nabídka správně aktualizovala.

Dále se podíváme na implementaci kontextových nabídek, což jsou nabídky, které se zobrazují při dlouhém stisknutí konkrétního pohledu, podobně jako pravé kliknutí v desktopovém prostředí. Android nabízí dva typy kontextových nabídek: starší plovoucí kontextovou nabídku a novější Kontextní akční režim (Contextual Action Mode), který byl představen v Androidu 3.0.

Plovoucí kontextová nabídka je starší metoda, která neumožňuje zobrazení více položek současně, a proto byla postupně nahrazena Kontextním akčním režimem. Tento režim umožňuje vybírat více položek a provádět akce na více položkách současně, což je výhodné v případech, kdy uživatel chce například odstranit více e-mailů v jedné akci.

Pro aktivaci Kontextního akčního režimu je potřeba v aplikaci provést několik kroků. Nejprve definujeme položky kontextové nabídky v souboru XML, který umístíme do adresáře res/menu. Následně vytvoříme metodu pro zobrazení kontextové nabídky při dlouhém stisknutí určitého prvku (například obrázku). Jakmile uživatel dlouze stiskne prvek, místo klasické akční lišty se zobrazí Kontextní akční lišta, která umožní interakci s daným prvkem.

Kontextní akční lišta se od akční lišty liší v tom, že umožňuje zobrazení akčních tlačítek pro konkrétní akce, které lze provést na vybraných položkách. Aktivace Kontextního režimu je tedy efektivní způsob, jak umožnit uživatelům interagovat s více položkami nebo provádět akce související s konkrétními položkami přímo v uživatelském rozhraní.

Důležité je, že při implementaci Kontextního režimu musíme dbát na to, aby naše aplikace podporovala i starší verze Androidu, které Kontextní akční režim ještě nepodporují. V těchto případech musíme mít záložní řešení, například starší plovoucí kontextovou nabídku, která bude fungovat na starších zařízeních.

Přechod mezi těmito režimy je jednoduchý a Android se postará o většinu logiky za nás, nicméně je důležité správně spravovat životní cyklus těchto režimů a dbát na jejich správné ukončení po dokončení akce, aby se uživatelské rozhraní nepletlo.

Jak správně pracovat s fragmenty v Androidu: Přehled implementace a komunikace mezi fragmenty

Vytvoření aplikace s několika obrazovkami je běžnou praxí v mobilním vývoji, a právě fragmenty jsou klíčovým nástrojem pro efektivní a flexibilní práci s uživatelským rozhraním v Androidu. Tento proces zahrnuje správnou implementaci fragmentů, jejich přepínání a komunikaci mezi nimi. K tomu, abyste správně zvládli práci s fragmenty, je potřeba pochopit několik důležitých kroků.

Začneme tím, že pro každý fragment vytvoříme samostatný layout. Nejprve vytvořte soubor fragment_one.xml, který obsahuje potřebné UI prvky pro první fragment. Druhý fragment je téměř identický, s jediným rozdílem v textovém popisku, například android:text="Fragment Two". Tento jednoduchý krok nastavuje základní strukturu pro oba fragmenty.

Pro každý fragment pak vytvoříme odpovídající třídu v jazyce Java. První třída FragmentOne bude vypadat následovně:

java
public class FragmentOne extends Fragment {
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_one, container, false); } }

Tato třída jednoduše načte layout pro první fragment při jeho vytvoření. Stejným způsobem vytvoříme i druhý fragment v souboru FragmentTwo, přičemž se změní pouze název layoutu a text.

Dále musíme přidat kontejner a tlačítko pro přepínání mezi fragmenty do hlavní aktivity. Pro tento účel upravíme soubor main_activity.xml, kde přidáme FrameLayout, který bude sloužit jako kontejner pro zobrazení fragmentů.

Ve třídě MainActivity pak inicializujeme obě instance fragmentů a nastavíme počáteční fragment, který se zobrazí při spuštění aplikace. Tento krok provedeme v metodě onCreate():

java
FragmentOne mFragmentOne; FragmentTwo mFragmentTwo; int showingFragment = 0; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mFragmentOne = new FragmentOne(); mFragmentTwo = new FragmentTwo(); FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.add(R.id.frameLayout, mFragmentOne); fragmentTransaction.commit(); showingFragment = 1; }

Tento kód nastaví první fragment jako výchozí, který se zobrazí při načítání aktivity. Fragmenty přidáváme pomocí metody add() v rámci transakce fragmentu a po dokončení transakce ji potvrzujeme metodou commit().

Přepínání mezi fragmenty zajistíme pomocí tlačítka, které bude volat metodu pro výměnu fragmentu. Zde je příklad kódu pro metodu switchFragment(), která zajišťuje přepínání mezi fragmenty:

java
public void switchFragment(View view) { FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); if (showingFragment == 1) { fragmentTransaction.replace(R.id.frameLayout, mFragmentTwo); showingFragment = 2; } else { fragmentTransaction.replace(R.id.frameLayout, mFragmentOne); showingFragment = 1; } fragmentTransaction.commit(); }

Tato metoda kontroluje, který fragment je momentálně zobrazen, a v závislosti na tom provádí výměnu fragmentu pomocí metody replace(). Opět je důležité zavolat metodu commit() pro potvrzení transakce.

Ačkoliv jsme si ukázali, jak manipulovat s fragmenty a přepínat je, je také nutné si uvědomit, že při manipulaci s fragmenty je možné využít zásobník zpětných akcí, známý jako back stack. Pokud přidáme fragment do back stacku, bude fragment při návratu zpět obnoven, místo aby byl znovu vytvořen. To lze dosáhnout přidáním volání addToBackStack() před zavoláním commit() při vytváření transakce.

Přidání fragmentu do zásobníku zpětných akcí:

java
fragmentTransaction.addToBackStack(null);

Tato volba umožňuje, aby uživatel mohl snadno přecházet mezi obrazovkami, aniž by byl fragment při každém návratu zničen.

Dalším důležitým aspektem práce s fragmenty je komunikace mezi nimi. Při vývoji aplikací, jako je e-mailový klient, může být potřeba předat data mezi dvěma fragmenty, například mezi seznamem e-mailů a detailním zobrazením jednoho e-mailu. Takovou komunikaci mezi fragmenty je nejlepší realizovat prostřednictvím hostitelské aktivity, která fragmenty spravuje a směruje zprávy mezi nimi.

V rámci této komunikace je dobré využít rozhraní (interface), které umožní fragmentům komunikovat s aktivitami. Pokud máme například fragment, který musí informovat jiný fragment o určitém stavu, použijeme rozhraní k předání požadované informace zpět do aktivity, která ji následně předá dalšímu fragmentu.

Taková struktura umožňuje čisté a snadno udržovatelné řešení, protože fragmenty jsou navzájem nezávislé a komunikují pouze prostřednictvím aktivity.

Nakonec je třeba si uvědomit, že při práci s fragmenty není nutné se omezovat pouze na dva fragmenty. Pokud potřebujete více fragmentů, stačí je jednoduše vytvořit a přidat do layoutu. Výhodou fragmentů je, že mohou být použity jak v orientaci na výšku, tak na šířku, což umožňuje přizpůsobit rozhraní různým velikostem obrazovek.

Jak funguje widget na domovské obrazovce a jak přidat funkci hledání do akčního panelu v Androidu?

Widgety na domovské obrazovce jsou mocným nástrojem pro zobrazení informací a interakci s uživatelem bez nutnosti otevření aplikace. Když přemýšlíme o jejich implementaci, začínáme od vytvoření rozložení widgetu, které musí splňovat určité požadavky, protože widgety jsou Remote View. V tomto kroku si ukážeme, jak vytvořit základní widget a přidat do něj funkcionalitu, která uživateli umožní interagovat s aplikací i z domovské obrazovky.

Prvním krokem je vytvoření souboru rozložení pro widget, což je standardní rozložení, ale s omezeními, která souvisejí s tím, že widget je vlastně vzdálený pohled (Remote View). V tomto příkladu používáme analogové hodiny, ale funkčnost lze snadno rozšířit podle potřeb aplikace. Soubory XML, které ukládají informace o widgetech, nám umožní nastavit výchozí nastavení widgetu, která se použijí při jeho prvním přidání na domovskou obrazovku. Mezi těmito nastaveními je i parametr updatePeriodMillis, který určuje, jak často se má widget aktualizovat. Tento interval je důležitý nejen z hlediska aktuálnosti dat, ale i pro šetření baterie, protože každé probuzení zařízení znamená větší spotřebu energie. Zde může pomoci přidání volitelného nastavení, které uživateli umožní rozhodnout se, jak často chce widget aktualizovat.

V souvislosti s implementací widgetu se musíme zaměřit na metodu onUpdate(), která je volána, kdykoli dojde k aktualizaci widgetu. Na základě této metody definujeme, co se stane, když uživatel klikne na widget – například jaký záměr (intent) bude proveden, když uživatel klikne na hodiny, aby se aplikace otevřela. Tento proces zahrnuje vytvoření PendingIntent, což je mechanismus, který zajišťuje, že událost bude zpracována v budoucnosti, v našem případě při interakci s widgetem.

Metoda onUpdate() probíhá pouze jednou za časový interval, který je nastavený v updatePeriodMillis. Tento interval je důležitý nejen pro správu paměti a energetickou náročnost, ale i pro synchronizaci více widgetů, které mohou být vytvořeny tímto poskytovatelem. Když je widget přidán, cyklus aktualizace začíná a všechny widgety tohoto typu se synchronizují s tímto intervalem.

Pokud widget nevyžaduje časté aktualizace, můžeme nastavit tento interval na nulu. Důležité je si uvědomit, že i v tomto případě bude metoda onUpdate() zavolána při prvním přidání widgetu na obrazovku, což umožňuje, aby byla aplikace správně zpracována již při jejím umístění.

Pokud chcete widgetu přidat větší flexibilitu, můžete přidat konfigurační aktivitu. Tento krok umožňuje uživatelům nastavit různé možnosti pro widget, jako je výběr rozložení, volby pro chování při kliknutí a podobně. Konfigurační aktivita se musí přidat do manifestu aplikace a také do souboru AppWidgetProviderInfo, kde se definuje, jaká aktivita bude použita k jeho nastavení.

Důležité je si uvědomit, že metoda onUpdate() nebude volána při použití konfigurační aktivity, protože tato aktivita je odpovědná za první nastavení widgetu. Konfigurační aktivita může zahrnovat volby, které uživatelům usnadní používání widgetu, například umožnění různých způsobů zobrazení informací nebo nabídnutí variant pro interakci s widgetem.

Dalším krokem, který může zlepšit uživatelský zážitek, je přidání funkce hledání do akčního panelu aplikace. Android 3.0 zavedl widget SearchView, který se doporučuje používat pro sjednocení uživatelského rozhraní v aplikacích. Tento widget umožňuje uživatelům hledat přímo z akčního panelu, což šetří čas a zlepšuje efektivitu.

Pro implementaci této funkce musíme přidat příslušné soubory do projektu, vytvořit menu pro akční panel a správně nakonfigurovat Search Manager API. Prvním krokem je přidání řetězců do souboru strings.xml, které definují text pro vyhledávání. Poté vytvoříme soubor menu_options.xml v adresáři res/menu a přidáme do něj widget SearchView. V metodě onCreateOptionsMenu pak nastavíme SearchManager pro použití v rámci aplikace. Tento widget se následně připojí k vyhledávacímu systému pomocí funkce setSearchableInfo.

Nejdůležitější částí tohoto procesu je správné napojení na SearchManager a nastavení atributů pro správné fungování vyhledávání v aplikaci. K tomu je potřeba také vytvořit soubor searchable.xml v adresáři res/xml, který definuje parametry pro hledání. Důležitým krokem je i vytvoření layoutu pro zobrazení výsledků hledání.

Pro vývojáře je důležité si uvědomit, že widgety, jak pro domovskou obrazovku, tak pro vyhledávání v akčním panelu, vyžadují pečlivé plánování a konfiguraci. Odpovídající testování a zajištění kvalitní uživatelské zkušenosti může významně zvýšit atraktivitu a funkčnost aplikace.

Jak efektivně pracovat s textovými soubory a databázemi v Android aplikacích?

V této kapitole se zaměříme na dvě zásadní metody práce s daty v Android aplikacích: čtení textových souborů z různých umístění a využití SQLite databází pro ukládání a správu dat. Ukážeme, jak načítat soubory uložené v aplikaci, jak používat složky res/raw a assets a jak pracovat s databází SQLite pro efektivní správu strukturovaných dat.

Pokud pracujete na Android aplikacích, musíte se naučit, jak správně číst soubory uložené v rámci aplikace, protože způsob přístupu k těmto souborům se liší podle umístění. Android poskytuje dvě hlavní metody pro práci s těmito soubory: složka res/raw a složka assets. Obě mají své specifické výhody a způsoby přístupu.

Příklad ukáže, jak načíst textový soubor ze složky raw a assets a zobrazit jeho obsah. Začněme tím, že vytvoříme projekt v Android Studiu a použijeme dvě složky pro textové soubory.

Pro začátek otevřete soubor activity_main.xml a nahraďte jeho obsah odpovídajícím layoutem. Poté vytvoříme složku raw v adresáři res pro textové soubory, které budou přístupné během běhu aplikace. Složku raw musíte ručně přidat, protože není součástí výchozího nastavení Android projektu.

  1. Vytvořte složku res/raw.

  2. V této složce vytvořte nový textový soubor, například raw_text.txt. Tento soubor bude obsahovat text, který se zobrazí v aplikaci.

  3. Stejným způsobem vytvořte složku assets. Tento proces je o něco složitější, ale Android Studio nabízí možnost ji snadno vytvořit přes nabídku File -> New -> Folder -> Assets Folder.

  4. Vytvořte soubor asset_text.txt v této složce. Text v něm bude zobrazen při spuštění aplikace.

Kód, který následuje, ukazuje, jak načíst obsah těchto souborů a zobrazit ho v TextView komponentách:

java
private String getText(InputStream inputStream) {
StringBuilder stringBuilder = new StringBuilder(); try { if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String newLine; while ((newLine = bufferedReader.readLine()) != null) { stringBuilder.append(newLine + "\n"); } inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } return stringBuilder.toString(); }

V metodě onCreate() přidáme kód, který načte texty z obou složek:

java
TextView textViewRaw = (TextView) findViewById(R.id.textViewRaw);
textViewRaw.setText(getText(this.getResources().openRawResource(R.raw.raw_text))); TextView textViewAsset = (TextView) findViewById(R.id.textViewAsset); try { textViewAsset.setText(getText(this.getAssets().open("asset_text.txt"))); } catch (IOException e) { e.printStackTrace(); }

Jak vidíte, hlavní rozdíl mezi těmito dvěma přístupy spočívá v tom, jakým způsobem získáváme přístup k souboru. Pro soubory v raw použijeme metodu openRawResource(), zatímco pro soubory v assets použijeme metodu open() z objektu getAssets(). Tento rozdíl je důležitý, protože přístup k souborům v assets neprobíhá za pomoci kompilace a tedy neexistuje žádná kompilace nebo verifikace jako u raw. To znamená, že při práci s assets je nutné vždy správně ošetřit chyby pomocí try/catch bloků.

SQLite databáze v Android aplikacích

Další důležitou součástí práce s daty v Android aplikacích je využití SQLite databází pro ukládání strukturovaných dat. SQLite poskytuje jednoduchý a efektivní způsob, jak ukládat data přímo na zařízení uživatele. Tento systém umožňuje provádět základní operace jako vytváření, čtení, aktualizaci a mazání (CRUD operace).

Pokud již máte zkušenosti s SQL databázemi, většina z toho, co znáte, bude platit i pro SQLite. Pokud jste se s nimi nikdy nesetkali, je dobré se nejprve seznámit se základními pojmy, jako jsou schémata, tabulky, kurzory a SQL dotazy.

Pro ukázku vytvoříme jednoduchou slovníkovou databázi, která bude uchovávat slova a jejich definice. Umožníme přidávat nová slova a aktualizovat existující definice. Zobrazení slov bude probíhat pomocí komponenty ListView, přičemž stisknutí slova v seznamu zobrazí jeho definici ve formě Toast zprávy. Dlouhý stisk na slovo pak provede jeho smazání.

Pro začátek vytvoříme nový projekt v Android Studiu s názvem SQLiteDatabase. Následně vytvoříme uživatelské rozhraní, které bude obsahovat dvě pole pro zadávání textu, tlačítko a seznam ListView.

Po vytvoření UI se zaměříme na práci s databází. Vytvoříme novou třídu DictionaryDatabase, která bude rozšiřovat třídu SQLiteOpenHelper a zajišťovat všechny operace s databází. Každá operace CRUD bude implementována jako samostatná metoda:

  • insert() pro vytvoření nové položky,

  • query() a rawQuery() pro čtení dat,

  • update() pro aktualizaci dat,

  • delete() pro smazání dat.

Důležité je také mít na paměti, že SQLite je vhodné používat pro ukládání relativně malých množství dat. Pro větší a komplexnější databázové systémy je lepší zvážit jiné možnosti, jako je Realm nebo Firebase.

Je důležité si také uvědomit, že práce s databází vyžaduje nejen správnou implementaci CRUD operací, ale i správné nakládání s databázovými transakcemi a správu připojení k databázi, aby byla aplikace efektivní a nevyčerpávala zbytečně systémové prostředky.