5. diel - Android Intent a aktivity - Java kód SumResultActivity
V predchádzajúcom kvíze, Kvíz - Nastavenie vzhľadu aktivity a intenty v Androide, sme si overili nadobudnuté skúsenosti z predchádzajúcich lekcií.
Celá dnešná lekcie bude, ako asi tušíte, o Java kódu
SumResultActivity
.
Java kód
SumResultActivity
Upravíme si ho teda do nasledujúcej podoby, ktorú si hneď podrobne vysvetlíme:
public class SumResultActivity extends AppCompatActivity { TextView labelNumber1; TextView labelNumber2; TextView labelResult; Button btnSend; int number1 = 0; int number2 = 0; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sum_result_activity); setTitle(R.string.sum_result_activity_title); labelNumber1 = findViewById(R.id.labelNumber1); labelNumber2 = findViewById(R.id.labelNumber2); labelResult = findViewById(R.id.labelResult); btnSend = findViewById(R.id.btnSend); btnSend.setOnClickListener(clickListener); try { Intent incomingIntent = getIntent(); number1 = incomingIntent.getIntExtra("number_1", 0); number2 = incomingIntent.getIntExtra("number_2", 0); labelNumber1.setText("" + number1); labelNumber2.setText("" + number2); labelResult.setText("" + (number1 + number2)); } catch (NullPointerException e) { labelNumber1.setText("?"); labelNumber2.setText("?"); Toast.makeText(this, R.string.incoming_intent_data_error, Toast.LENGTH_LONG).show(); } } }
Chýbajúce premennú clickListener
si doplníme za
chvíľu.
Máme tu pripravené atribúty pre jednotlivé komponenty aktivity, ktoré si
inicializujeme v onCreate()
. Tiež tu máme atribúty pre uchovanie
2 čísel, ktorá ale bola zadaná v predchádzajúcej aktivite. Dostávame sa k
onej zaujímavej časti.
Príjem dát z aktivity
SumActivity
V každej aktivite získame volaním getIntent()
intent, ktorým
bola daná aktivita otvorená. My toto vykonávame v metóde
onCreate()
a intent ukladáme do premennej
incomingIntent
. Z nej potom pomocou kľúčov získame naše
čísla určená k súčtu. Zadávame samozrejme tie kľúče, pod ktoré sme si
dáta uložili v SumActivity
.
Získané hodnoty potom zobrazujeme v dvoch TextView
a v treťom
zobrazujeme ich súčet. Celý popísaný postup je v bloku try
-
catch
, ktorým odchytávajú prípadnú výnimku
NullPointerException
. Táto výnimka bude vyvolaná v prípade, že
"prichádzajúci" intent, uložený do premennej incomingIntent
,
bude obsahovať hodnotu null
. Vo chvíli, kedy by sme na premenné
incomingIntent
, s hodnotou null
, zavolali metódu
getIntExtra()
, došlo by bez ošetrenia výnimky k pádu aplikácie
za behu.
Udalosť kliknutie na tlačidlo
Máme tu tiež ďalší sľúbený alternatívny spôsob obsluhy kliknutí na tlačidlo.
Odoslanie výsledku súčtu späť do SumActivity
je
realizované opäť Java kódom, podobne ako v SumActivity
. Vtedy
sme tlačidlu priradili inline zápisom OnClickListener
vytvorením
anonymné
triedy. Hovorili sme si, že tento prístup neumožňuje opätovné
použitie kódu. Tu bude postup podobný. Rozdiel bude v tom, že vytvoríme
inštanciu Listener, ktorú možno priradiť ľubovoľnému počtu
elementov.
Do kódu za deklaráciu premenných pridáme:
View.OnClickListener clickListener = new View.OnClickListener() { @Override public void onClick(View v) { if (v.getId() == R.id.btnSend) { Intent resultIntent = new Intent(); resultIntent.putExtra("result_from_activity_sum", number1 + number2); setResult(RESULT_OK, resultIntent); finish(); } } };
Tento listener v metóde onCreate()
nastavujeme jedinému
tlačidlu. Listener povinne prepisuje metódu onClick()
, ktorá je
volaná s parametrom typu View
. Toto View
je
referencií na element, ktorý bol v GUI stlačený.
V metóde onClick()
potom už len testujeme, či sa ID
stlačeného elementu rovná ID tlačidlá pre odoslanie odpovede (teda či
udalosť kliknutí vyvolalo toto tlačidlo).
Pretože sme tento listener priradili iba jedinému objektu, nie je táto podmienka ani potrebná, pretože iná možnosť nastať nemôže. Je ju však vhodné uviesť, pretože keď by sme niekedy pridali nejaký ďalší klikacie prvok, mohli by sme na ňu zabudnúť a také chyby sa zle hľadajú:)
Pri porovnaní tohto spôsobu obsluhy udalosti s anonymný triedou v
SumActivity
je zrejmé, že tento má výhodu vo svojej
znovupoužitelnosti. Ale stále má nevýhodu vo väčšom množstve a menšie
prehľadnosti, než u spôsobu s atribútom android:onClick
priamo
v XML.
Odoslanie odpovede do
SumActivity
Po kliknutí sa chceme vrátiť do predchádzajúcej aktivity a poslať do
nej výsledok. Popísaný OnClickListener
v metóde
onClick()
teda vytvára intent, ktorý neobsahuje žiadnu akciu. Tu
totiž vytvárame intent iba za účelom prenosu dát medzi aktivitami. V
ďalšom riadku Intent tieto dáta nastavujeme s kľúčom z textového
reťazca. Vďaka tomuto kľúču dáta vyzdvihneme v SumActivity
,
kam ich pošleme.
Ďalším riadkom voláme metódu setResult()
. Minule sme si v
tejto súvislosti opisovali dve konštanty:
RESULT_OK
aRESULT_CANCELED
.
Druhým parametrom je vytvorený intent s dátami pre
SumActivity
.
Posledným riadkom aktivitu SumResultActivity
zavrieme a
vrátime sa späť do SumActivity
.
Úprava Java kódu aktivity
SumActivity
V aktivite SumActivity
sme deklarovali metódu
sendData()
, ktorú sme nechali prázdnu. Teraz, po vytvorení
aktivity SumResultActivity
, môžeme túto metódu doplniť:
private void sendData() { Intent sendIntent = new Intent(this, SumResultActivity.class); sendIntent.putExtra("number_1", number1); sendIntent.putExtra("number_2", number2); startActivityForResult(sendIntent, 1); }
Na prvom riadku vytvárame explicitné intent, vyjadrujúce konkrétny zámer
- spustiť SumResultActivity.class
.
V nasledujúcich dvoch riadkoch priraďujeme dáta so zadanými číslami. Každé číslo do Intent vkladáme s kľúčom, tvoreným textovým reťazcom. Vďaka kľúčom si čísla "vyzdvihneme" v aktivite, ktorú intent otvoríme.
Posledným riadkom voláme metódu startActivityForResult()
,
čím aktivitu SumResultActivity
otvoríme s tým, že po jej
zatvorení budeme v aktivite SumActivity
očakávať odpoveď s
výsledkom súčtu. Tá prijíma dva parametre:
- vytvorený intent
requestCode
- ide o hodnotu typuint
, označujúci dôvod skoku z aktivitySumActivity
do inej aktivity.
requestCode
Kedykoľvek otvoríme inú aktivitu volaním
startActivityForResult()
, bude po jej zatvorení v pôvodnej
aktivite volaná metóda onActivityResult()
, ktorú si hneď
uvedieme. Volanie tejto metódy upozorňuje na zatvorenie aktivity, ale
nehovorí, o akú aktivitu išlo, nič o dôvode jej otvorenia a aké dáta
máme očakávať. Práve vďaka requestCode
po prijatí odpovede
vieme, aká aktivita bola otvorená a následne zatvorená a tým pádom aj ako
na odpoveď reagovať, alebo aké dáta v odpovedi očakávať.
Môže sa aj stať, že síce vieme, ktorá aktivita bola zatvorená (napr.
Preto, že inú aktivitu ani neotvárame), ale táto aktivita môže mať
schopnosť plniť viac rôznych úloh s rôznymi typmi návratnými dát. Vďaka
requestCode
potom vieme, aký úloha bol vykonaný, teda aké dáta
v odpovedi očakávať a ako ich spracovať.
Deklarácia aktivít v
AndroidManifest.xml
Ak teraz našu aplikáciu Activities
spustíme a pokúsime sa
otvoriť prvým tlačidlom SumActivity
, dôjde k pádu aplikácie s
výnimkou ActivityNotFoundException
. V Android Štúdiu, pohľadom
do logcatu, uvidíme s nastaveným filtrom na zobrazenie + errorov niečo
takéto:
Vo výpise logcatu je dokonca upozornenie na to, že aktivita nie je
deklarovaná v súbore manifestu. Otvoríme teda súbor
AndroidManifest.xml
:
Na obrázku je vidieť obsah tohto súboru po jeho automatickom vygenerovaní Android Štúdiom pri vytvorení nového projektu. Do tejto chvíle nebolo nutné tento súbor akokoľvek upravovať.
Po pridaní akékoľvek ďalšie aktivity do projektu je nutné ju v manifeste deklarovať!
My sme vytvorili aktivity SumActivity
a
SumResultActivity
. Obe teda do manifestu pridáme nasledujúcim
kódom za deklaráciu MainActivity
:
<activity android:name=".SumActivity" android:parentActivityName=".MainActivity"> </activity> <activity android:name=".SumResultActivity" android:parentActivityName=".MainActivity"> </activity>
Upravený súbor AndroidManifest.xml
bude teda vyzerať
takto:
parentActivityName
Atribút android:parentActivityName=".MainActivity"
nie je
povinný. Slúži pre zobrazenie šípky v ľavej časti toolbaru aktivity.
Táto šípka slúži pre navigáciu späť do tej aktivity, ktorá je uvedená
v hodnote atribútu. Nasledujúce obrázky ukazujú rozdiel - prvý zobrazuje
stav bez parametra a druhý s parametrom:
Všimnite si že v kóde manifeste z SumResultActivity
sa touto
šípkou vraciame priamo do hlavnej aktivity a nie do
SumActivity
.
Používaní odkazov na reťazce
Iste ste si všimli nastavovanie textu zobrazovaným správam a objektom
TextView
. Nemalo by vás prekvapiť, že text nie je nastavený "na
tvrdo", ale je použitý odkaz do resources
projektu.
Pri vytvorení projektu Android Studio, spolu s ďalšími súbormi,
vygeneruje súbor strings.xml
v priečinku
res/values/
. Ten slúži na ukladanie textových reťazcov, ktoré
tak možno v kóde použiť viackrát a na ktoré v kóde odkazujeme. Je tak
najmä kvôli centralizáciu všetkých reťazcov na jedno miesto, čím
môžeme potom aplikáciu jednoducho preložiť do iného jazyka.
Poďme si na príklade ukázať, ako ľahko možno v Android Štúdiu z
použitého textového reťazca vytvoriť položku v resources
. V
metóde onCreate()
máme blok try
-
catch
, ktorým ošetrujeme vznik výnimky, pri ktorej bude
užívateľovi zobrazí správa:
Toast.makeText(this, R.string.incoming_intent_data_error, Toast.LENGTH_LONG).show();
Takto by vyzerala predchádzajúca ukážka bez použitia odkazu do
resources
:
Toast.makeText(this, "Chyba přijatých dat...", Toast.LENGTH_LONG).show();
Ak chceme z textového reťazca ľahko vytvoriť odkaz na, zatiaľ
neexistujúce, položku v res/values/strings.xml
, klikneme na
reťazec tak, aby na ňom bol kurzor. Vľavo sa objaví žltá žiarovka:
Na túto žiarovku klikneme ľavým tlačítkom av menu zvolíme Extract string resource:
V otvorenom okne Extract Resource s predvyplneným textovým
reťazcom napíšeme do prvého riadku názov, pod akým bude text uložený v
súbore strings.xml
, a potvrdíme tlačidlom OK:
Na koniec súboru strings.xml
bude pridaný nový riadok:
Rovnaký spôsob použijeme aj v XML návrhu GUI a nastavovali by sme takto
aj farby. Ak nastavíme niekde nejakému elementu farbu priamo, môžeme ju
neskôr, pomocou žltej žiarovky, extrahovať do súboru
res/values/colors.xml
rovnako ako v prípade textových
reťazcov.
Už vieme otvárať iné aktivity a odovzdávať údaje medzi nimi. V
ďalších lekciách kurze si popíšeme funkcie ostatných tlačidiel
ukážkové aplikácie Activities
. Prvých päť tlačidiel bude
explicitnými Intent otvárať nami vytvorené aktivity.
Každá z týchto aktivít bude mať nejakú funkčnosť, spočívajúce vo
vytváraní implicitných Intent, na zapojenie do hry aj
systém a jeho defaultný aktivity, ako napr. Zobrazenie mapy, odosielanie SMS
alebo fotoaparát.
Nižšie je k stiahnutiu projekt s doplnenou aktivitou
SumActivity
a aktivitou SumResultActivity
.
Nabudúce, v lekcii Android Intent a aktivity - MapActivity - Zobrazenie mapy , vytvoríme aktivitu MapActivity pre zobrazenie zemepisných súradníc na mape.