IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

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 a
  • RESULT_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 typu int, označujúci dôvod skoku z aktivity SumActivity 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:

Android intent a aktivity

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:

Android intent a aktivity

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:

Android intent a aktivity

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:

Android intent a aktivity Android intent a aktivity

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:

Android intent a aktivity

Na túto žiarovku klikneme ľavým tlačítkom av menu zvolíme Extract string resource:

Android intent a aktivity

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:

Android intent a aktivity

Na koniec súboru strings.xml bude pridaný nový riadok:

Android intent a aktivity

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.


 

Predchádzajúci článok
Kvíz - Nastavenie vzhľadu aktivity a intenty v Androide
Všetky články v sekcii
Android intent a aktivity
Preskočiť článok
(neodporúčame)
Android Intent a aktivity - MapActivity - Zobrazenie mapy
Článok pre vás napísal Pavel
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje programování v Javě, hlavně pro Android. Mezi jeho další zájmy patří Arduino, Minecraft.
Aktivity