Naučte sa vyvíjať aplikácie pre Android za 14 dní – aplikácia s dvomi aktivitami

2

V budúcom pokračovaní už budeme spúšťať a ladiť aplikáciu na reálnom zariadení, pričom ukážeme postup pre všetky obidve varianty, čiže smartfóny s podporou služieb Google a taktiež aj nové smartfóny Huawei bez podpory týchto služieb. Aby však bolo čo spúšťať a ladiť najskôr v tomto dieli vytvorme aplikáciu, ktorá na rozdiel od doterajších cvičných projektov už bude ako tak zmysluplná a budú sa v nej spracovávať nejaké údaje. 

Pripomenieme, čo je aktivita: Aktivita je hlavná trieda, ktorá sa používateľom zobrazí  po spustení aplikácie. Aplikácia môže pozostávať z viacerých aktivít, ktoré si navzájom odovzdávajú údaje. Aktivity umožňujú používateľom cez grafické rozhranie (GUI) prijímať informácie od aplikácie a ovládať ju. Cez aktivitu sa spravidla implementuje viac, alebo menej komplexná čiastková úloha, ktorú má používateľ realizovať, napríklad vyplniť formulár, nastaviť parametre, vybrať si položku zo zoznamu a podobne. Trieda Activity je predurčená k tomu, aby zobrazovala používateľské rozhranie a zachytávala interakcie používateľa cez toto rozhranie. Aktivita by mala byť navrhnutá tak, aby umožnila používateľovi sústrediť sa na jednu vec, ktorú momentálne potrebuje realizovať, napríklad napísať a poslať textovú správu, zadať kontaktné údaje a podobne.

Námetom aplikácie bude výpočet indexu telesnej hmotnosti BMI na základe zadanej výšky a hmotnosti osoby. Vzorec na výpočet je 

BMI hodnota = Hmotnosť v kg : (výška v m)2

Vytvorte projekt s hlavnou aktivitou typu EmptyActivity. Na ploche obrazovky hlavnej aktivity budú ovládacie prvky na zadanie údajov. Výsledky sa zobrazia na obrazovke druhej aktivity.

Začnime vytvárať používateľské rozhranie hlavnej aktivity, na ktorej bude používateľ zadávať údajeNa zobrazenie popisov polí pre zadanie textu sú v príklade použité prvky typu TextView. Okrem typu hodnoty naznačíme používateľovi aj to, v akých jednotkách aplikácia príslušnú hodnotu očakáva Používateľ bude interagovať s dvoma prvkami typu EditText na zadanie výšky a váhy a zadanie potvrdí tlačidlom, teda prvkom typu Button

Pre rozmiestnenie prvkov v súbore activity_main  využijeme vizuálny kontejner LinearLayout tentokrát s vertikálnym rozmiestnením prvkov. Nakoľko bude používateľ zadávať len čísla, nakonfigurujeme prvok EditText tak, aby bolo prostredníctvom neho možné zadať len textový reťazec pozostávajúci z číslic. Zariadi to parameter android:inputType="number"

Kompletný návrhový kód v súbore activity_main.xml bude:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
 
    <TextView
        android:text="@string/et_labelVyska"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
 
    <EditText
        android:id="@+id/etVyska"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number" />
 
    <TextView
        android:text="@string/et_labelVaha"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
 
    <EditText
        android:id="@+id/etVaha"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:inputType="number" />
 
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="buttonClicked"
        android:text="@string/button_title" />
</LinearLayout>

Tento príklad už považujeme za prvú reálnu aplikáciu, preto nebudeme vkladať textové reťazce do priamo prvkov typu TextView, ale do resourceov, teda do súboru /res/values/strings.xml

<resources>
    <string name="app_name">BMI kalkulacka</string>
    <string name="button_title">Výpočet BMI</string>
    <string name="et_labelVyska">Výška [cm]:</string>
    <string name="et_labelVaha">Váha [kg]:</string>
    <string name="nespravne_cislo">Musíš zadať číselnú hodnotu</string>
    <string name="zobraz_bmi">Tvoje BMI je %1$.2f.</string>
</resources>

Zobrazenie textových reťazcov vo vývojovom prostredí. Vľavo translate editor, vpravo textové reťazce aplikácie ako XML dokument

Zatiaľ máme podčiarknutú deklarovanú metódu na obsluhu udalosti zatlačenia tlačidla, pretože ju nemáme v Java kóde hlavnej aktivity

Aplikačná logika

Obsluha udalosti zatlačenia tlačidla sa odohráva v metóde buttonClicked. V kóde metódy je najskôr potrebné zistiť a skontrolovať zadané údaje. V našom prípade je táto kontrola na prvý pohľad duplicitná, nakoľko používateľ môže zadávať len číselné hodnoty. Avšak používateľ je nevyspytateľný môže napríklad zadať záporné číslo, alebo inú problematickú hodnotu, trebárs nulovú výšku, ktorá následne spôsobí delenie nulou... Preto aplikácia za platný údaj považuje výšku nad 50 cm. 

public void buttonClicked(View button) 
{
      int vyska = dajCislo(R.id.etVyska);
      int vaha = dajCislo(R.id.etVaha);
      if(vyska < 50)oznamNespravneCislo(R.id.etVyska);
      else if(vaha < 0)oznamNespravneCislo(R.id.etVaha);
      else vypocetBMI(vyska, vaha);
}

V reálnej aplikácii by ste používateľovi oznámili viac detailov, prečo je ním zadaný údaj neplatný. V tejto aplikácii oznámime len ktorý údaj je neplatný, zadaný údaj sa vynuluje a aplikácia naň prenesie fokus, čiže používateľ môže začať zadávať údaj nanovo.

protected void oznamNespravneCislo(int nID)
{
     Toast.makeText(this, R.string.nespravne_cislo, 
       Toast.LENGTH_SHORT).show();
     EditText etVstup = ((EditText)findViewById(nID));
     etVstup.setText("");
     etVstup.requestFocus();
}

Používateľ de facto zadáva textový reťazec, ktorý je potrebné prekonvertovať na číslo. To je úlohou metódy dajCislo. Na zistenie inštancie prvkov EditView je použití metóda findViewById(int id). Parameter je identifikátor požadovaného prvku. Text následne prekonvertujeme na celé číslo. Ak sa konverzia nepodarí, vráti metóda hodnotu -1 a tá sa následne v metóde buttonClicked identifikuje ako nesprávna a vygeneruje sa oznam

protected int dajCislo(int nID)
{
      EditText etVstup = ((EditText)findViewById(nID));
      String strVstup = etVstup.getText().toString();
      int nCislo = -1;
      try
      {
             nCislo = Integer.parseInt(strVstup);
      }
      catch(NumberFormatException e){}
      return nCislo;
}

Pre komunikáciu medzi entitami aplikácií sa využíva Intent. Intent (v preklade zámer)  je trieda, ktorá obsahuje runtime väzby medzi jednotlivými zložkami, napríklad aktivitami a argumenty na odovzdanie parametrov. Intent sa odovzdá operačnému systému a ten sa snaží zariadiť, aby bol zámer splnený. V prípade ak je k dispozícii viac aktivít schopných splniť príslušný zámer, systém umožní voľbu aktivity používateľovi. Metóda putExtra preberá dva argumenty textový reťazec s unikátnym identifikátorom objektu na odovzdanie parametra a samotný objekt, ktorý môže tvoriť elementárna hodnota alebo vhodný serializovateľný objekt. V našom prípade budeme odovzdávať hodnotu BMI prostredníctvom premennej typu float, nakoľko BMI je desatinné číslo.

protected void vypocetBMI(int vyska, int vaha)
{
      float bmi;
      float vyskam = (float)vyska/100;
      bmi = vaha/(vyskam * vyskam);
      Intent intent = new Intent(this, VypisBmiActivity.class);
      intent.putExtra(VypisBmiActivity.BMI, bmi);
      startActivity(intent);
}

Kompletný zdrojový kód triedy hlavnej aktivity aplikácie, teda tej, kde sa zadávajú a spracovávajú údaje bude:

package com.example.bmikalkulacka;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    public void buttonClicked(View button)
    {
        int vyska = dajCislo(R.id.etVyska);
        int vaha = dajCislo(R.id.etVaha);
        if(vyska < 50)oznamNespravneCislo(R.id.etVyska);
        else if(vaha < 0)oznamNespravneCislo(R.id.etVaha);
        else vypocetBMI(vyska, vaha);
    }
    protected void oznamNespravneCislo(int nID)
    {
        Toast.makeText(this, R.string.nespravne_cislo,
                Toast.LENGTH_SHORT).show();
        EditText etVstup = ((EditText)findViewById(nID));
        etVstup.setText("");
        etVstup.requestFocus();
    }
 
    protected int dajCislo(int nID)
    {
        EditText etVstup = ((EditText)findViewById(nID));
        String strVstup = etVstup.getText().toString();
        int nCislo = -1;
        try
        {
            nCislo = Integer.parseInt(strVstup);
        }
        catch(NumberFormatException e){}
        return nCislo;
    }
 
    protected void vypocetBMI(int vyska, int vaha)
    {
        float bmi;
        float vyskam = (float)vyska/100;
        bmi = vaha/(vyskam * vyskam);
        Intent intent = new Intent(this, VypisBmiActivity.class);
        intent.putExtra(VypisBmiActivity.BMI, bmi);
        startActivity(intent);
    }
 
}

Vytvorenie novej aktivity

Následne je potrebné vytvoriť novú aktivitu pre výpis vypočítaného BMI. Pre vytvorenie aktivity, ktorá obsahuje aj XML definičný súbor používateľského rozhrania môžete s výhodou použiť sprievodcu vytvorenia aktivity. Spustíte ho cez menu New -> Activity -> Empty Activity. Na vytvorenie novej aktivity je k dispozícii široká ponuka šablón

Aktivitu môžete pomenovať napríklad VypisBmiActivity. Od názvu aktivity sa odvodí názov layoutu, teda súboru s kódom jej používateľského rozhrania. Aktivita bude potrebovať tento definičný súbor v zložke res, preto sa uistite, či je označená voľba Generate Layout File.

 

Zdrojový kód triedy novej aktivity  VypocetBmiActivity.java nájdete v zložke src, vo vnorenej zložke com.example.nazovprojketu.

package com.example.bmikalkulacka;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
 
public class VypisBmiActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_vypis_bmi);
    }
}

Súbor pre návrh používateľského rozhrania activity_vypis_bmi.xml vytvorený sprievodcom v tejto aplikácii nevyužijeme. Prvky na výpis vytvoríme ako objekty v Java kóde

Informácie o vytvorenej aktivite budú pridané aj do aplikačného manifestu v súbore AndroidManifest.xml, ktorý nájdete v zložke app -> manifests

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.bmikalkulacka">
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".VypisBmiActivity"></activity>
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>

Metóda Activity.startActivity odovzdá systému príslušný Intent a oznámi mu, že má spustiť nejakú Activity. Tým sa dejstvo v hlavnej aktivite končí a na popredie vystúpi aktivita VypisBmiActivity

Začnime teda tvoriť kód triedy novej aktivity. V hlavnej aktivite sme v metóde vypocetBMI()  odkazovali na textový reťazec s unikátnym identifikátorom objektu na odovzdanie parametra BMI druhej aktivite. Pripomeňme si kód tejto metódy:

protected void vypocetBMI(int vyska, int vaha)
 
   float bmi;
   float vyskam = (float)vyska/100;
   bmi = vaha/(vyskam * vyskam);
   Intent intent = new Intent(this, VypisBmiActivity.class);
   intent.putExtra(VypisBmiActivity.BMI, bmi);
   startActivity(intent);

Preto musíme v kóde aktivity VypisBmiActivity tento konštantný reťazec vytvoriť

public static final String BMI = "bmi";

V metóde onCreate preberie aktivita Intent vytvorený hlavnou aktivitou. Pomocou metódy getFloatExtra získame hodnotu BMI. Druhý parameter obsahuje implicitnú hodnotu ak by sa vlastnosť s daným kľúčom v intente nenachádzala.

Intent i = getIntent();
float bmi = i.getFloatExtra(BMI, -1);

V metóde zobrazBMI zobrazí aktivita hodnotu BMI ako súčasť textového reťazca. Všimnite si v súbore /res/values/strings.xml reťazec obsahujúci formátovaciu sekvenciu %1$.2f ktorá predpisuje, že prvý parameter sa zobrazí ako desatinné číslo (f - float) s presnosťou na dve desatinné miesta (.2). 

<string name="zobraz_bmi">Tvoje BMI je %1$.2f.</string>

Kompletný zdrojový kód triedy novej aktivity je

package com.example.bmikalkulacka;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TextView;
 
public class VypisBmiActivity extends AppCompatActivity {
    public static final String BMI = "bmi";
    
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        TextView tv = new TextView(this);
        setContentView(tv);
        Intent i = getIntent();
        float bmi = i.getFloatExtra(BMI, -1);
        zobrazBMI(bmi, tv);
    }
 
    protected void zobrazBMI(float bmi,  TextView tv)
    {
        Resources res = getResources();
        String text = res.getString(R.string.zobraz_bmi, bmi);
        tv.setText(text);
    }
 
}

 

Teraz môžete aplikáciu vyskúšať. Vľavo je hlavná aktivita zobrazená po spustení aplikácie určená na zadanie parametrov na výpočet BMI. Vpravo je aktivita, ktorá vypíše vypočítané BMI

Samozrejme aktivitu na výpis môžete vylepšiť, namiesto suchého konštatovania hodnoty môžete dať komentár, či sa jedná o správnu hmotnosť, prípadne obezitu, zobraziť hodnotu na grafe a podobne

Ak si to zrekapitulujeme, po siedmych častiach seriálu viete vytvoriť zmysluplnú aj keď zatiaľ nie príliš komplexnú aplikáciu, poznáte filozofiu dizajnu a viete z akých súborov pozostáva projekt. V budúcom pokračovaní ukážeme ako aplikáciu nahrať do smartfónu, tam ju spustiť a ladiť.

Prehľad dielov seriálu

1 deň – Prvá aplikácia 

2 deň – Možnosti emulátorov 

3 deň - Zorientujte sa v projekte aplikácie

4 deň – Princípy dizajnu a škálovania

5 deň – Uporiadanie prvkov používateľského rozhrania

6 deň – Obsluha udalostí

Zobrazit Galériu

Luboslav Lacko

Všetky autorove články
Android Vývoj aplikácií Android aplikácia

2 komentáre

Code style reakcia na: Naučte sa vyvíjať aplikácie pre Android za 14 dní – aplikácia s dvomi aktivitami

24.3.2020 09:03
Prosim neucte ludi pisat cokolvek v nasom rodnom jazyku :/ IDcka, nazvy funkcii, nazvy premennych, nazov projektu, nazov Activity... vsetko by malo byt v anglictine. Nazvy stringov su s podtrzitkami, IDcka pre Views su v CamelCase - to by malo byt urcite zjednotene, vsetky nazvy stringov, drawables, a inych resoources a IDcka by mali byt v jednotnej notacii - idealne s podtrzitkami. Otvaracia zatvorka funkcie na samostatnom riadku tiez nie je uplne Java/Kotiln styl, ale tu asi kazdemu podla chuti :)
Reagovať

RE: Code style reakcia na: Code style

24.3.2020 10:03
Jeden diel budem určite venovať aj štábnej kultúre, ale na názvoch premenných samozrejme bez diakritiky v rodnom jazyku nevidím nič zlé. Skúsil som raz urobiť ekonomický softvér a tam prekladať výstižné názvy premenných do angličtiny a bolo to o ničom. Ako programátor neekonóm som akotak pochopil zadanie a v mojich prekladoch by sa nevyznal fakt nikto.
A spočiatku budem kvôli zjednodušeniu a názornosti robiť aj väčšie prehrešky, napríklad textové reťazce napevno v XML kóde Treba si uvedomiť že mnohí začiatočníci pracovali v scratchi ktorý mali lokalizovaný celý vrátane príkazov.
Reagovať

Pridať komentár

Mohlo by vás zaujímať

Mohlo by vás zaujímať