Android alkalmazásfejlesztés 2. rész: alapozunk

Az 1. résztől fellelkesedve ideje vágni egy féket, lefordulni a box utcába és megismerkedni az építőelemekkel!

Bevezetés

Első rész itt található: Android alkalmazásfejlesztés 1. rész: számológép

Kicsi visszakacsintás:
Az első részben kedvcsinálónak elkészítettünk egy alap számológép alkalmazást. Ezen keresztül megismerkedtünk az Android Studio-ban történő projekt létrehozással, alapszinten a View-k szerepével és kitekintettünk az Activity-k fogalmára is.

Az előző pörgősebb hangvételű cikk után most kicsit lassítunk, és időt szánunk az alapokra. Természetesen nem lesz idő mindent mélyrehatóan ismertetni, így csak a fontosabb dolgokról fogunk beszélni. Itt le is szögezném, hogy ezt a cikksorozatot nem azért hoztam létre, hogy valaki nulla programozás tudással nekiüljön és a végére profi legyen. Bizonyos alapszintű ismeretekre szükség van, hogy valaki értse a cikket. Ahhoz, hogy valaki Androidra fejlesszen, erős Java tudás is szükséges, amit ebben a sorozatban nem fogok mélyen ismertetni. Próbálom a kódot egyszerűsíteni és csak egyszerű vagy elhagyhatatlan dolgok, vezérlési elemek használatán keresztül ismerjük meg a témakört.

Ebben a részben nem lesz külön teljes alkalmazás, de megismerkedünk több fontos dologgal is, ami elengedhetetlen az Android fejlesztéshez. Három részre tagoljuk ezt a részt.
Az első egy egyszerűbb bemutatása lesz az Android Studio-nak. Projekt létrehozása, alkalmazástesztelés, APK generálás és hasonlók.
A második részben mélyebb ismereteket szerzünk a View-król, megnézzük, mi a különbség a View és a ViewGroup között, kicsit kitérünk a gyakori attribútumokra is.
A harmadik részben pedig átvándorlunk Java oldalra, és pár fontos témakört érintünk. Az Activity-k a Fragment-ek és az Intent és Intent Filterek az alap építőelemei egy alkalmazásnak, róluk fogunk beszélni.

Mindegyik téma, amit felsoroltam nagyon mély, és nagyon sokat lehetne róluk beszélni. A teljesség igénye nélkül fogjuk átnézni őket, ha bárhol van olyan dolog, ami nem érthető, vagy pont hozzá tudnál fűzni valamit, amit fontosnak érzel és kihagytam, akkor ezekre mind lehetőség van komment formájában.

Hirdetés

Android Studio

Szinte bármilyen gazda oprendszerrel dolgozunk, nagyon egyszerű beszerezni a fejlesztéshez szükséges környezetet. Maga az IDE letölthető a hivatalos oldalról, developer.android.com/studio, valamint maga a Studio képes a szükséges SDK-k letöltésére.
Aki használt már IntelliJ IDEA-t annak ismerős lehet a felület, hiszen az IntelliJ adja az alapját a Studionak.

A Studio megnyitása után egyből van pár lehetőségünk a kezdésre.
Kezdhetünk új projektet, megnyithatunk már meglévőt, kapcsolódhatunk Version Control-hoz, sőt, akár APK-t is lehet debugolni vagy Eclipse ADT projektet is be tud húzni az IDE.

Az első részben már átmentünk a projekt létrehozásánál, így arra annyira nem térnék ki. Egy momentumról szeretnék itt beszélni. A varázsló utolsó pontja egy Activity-választó. Itt én általában az Empty Activity-t szoktam választani, de ezek az Activity-k megkönnyíthetik az elindulást egy-egy alkalmazásnál. Például nem mindegy, hogy a Maps-et nekünk kell beleherélni, vagy alapból legenerálja az IDE.

Ha megnyílt az IDE vagy az új projekt, vagy egy régi importált, kezdődhet is a fejlesztés. Van rá esély, hogy olyan SDK szintet választottunk, ami nincs letöltve. Ebben az esetben szól a Studio, hogy nem találja és fel is ajánlja, hogy telepíthető. Ezen szépen végig lehet zongorázni és már vissza is lehet térni a fejlesztéshez.
Előfordulhat még dependecy conflict. Ilyenkor egy ehhez hasonló hibát kapunk:

Ezt egyszerűen megoldhatjuk. A build.gradle file-ba a dependeciák közé fel kell venni a következő sort: compile 'com.android.support:support-annotations:27.1.1' Természetesen a verziószám változhat.

Ha minden hibát kiirtottunk, ideje belenézni pár, a fejlesztéshez fontos dologba. Az első részben említettem, hogy van egy Drag and Drop verziója a layout szerkesztőnek. Ez egy speciális Layout típusnál sokat jelenthet egy kezdő számára. Vizuális visszajelzést kap egyből, és mint egy képszerkesztő, lehet felpakolni vagy leszedni a dolgokat. A Linear vagy Relative Layout esetében ez nem az igazi, de így is könnyíthet a dolgokon. A ConstraintLayout segítségével pedig egy gyors eszköz az egyszerű responsive UI elkészítéséhez. Ezekkel a Layoutokról a következő oldalon fogunk megismerkedni.

A fejlesztés végső fázisai közé tartozik magának az alkalmazásnak a kipróbálása. Két módot ad rá a Studio. Az egyik egy emulátor, így az adott API szinttel nem rendelkező készülékek tulajdonosai is ki tudják próbálni az alkalmazásukat. Értelemszerűen a nagy zöld gomb megnyomása után a "Create New Virtual Device" gomb használatával létrehozhatunk egy emulátort. Az adott image file letöltése után használhatóvá válik az emulátor és tesztelésre kész az alkalmazás.

A másik mód a saját eszközön való tesztelés. Ennek a módja egyszerűbb, de ugye számolni kell azzal, hogy jó API szinttel rendelkezzen a készülékünk. Például nem lehet tesztelni egy Android P-re megírt kódot egy Android 7.0-s rendszerrel rendelkező eszközön. Az adott eszközön bekapcsoljuk a fejlesztői beállításokat. Majd a fejlesztői beállításokon belül ADB Debugging. Majd a fejlesztői géppel való összekötés után tesztelhetjük is. Szintén a nagy zöld gomb megnyomására van szükség majd a megfelelő készülék kiválasztása után indul is a buildelés és a telepítés.

Amennyiben minden jónak látszik, ideje APK-t generálni. Build menüpont majd Build APK(s) vagy Generate Signed APK. A különbség pedig eléggé kézenfekvő. A sima APK nem rendelkezik digitális aláírással. Nem számít biztonságos alkalmazásnak. Míg a digitálisan aláírt APK az adott fejlesztőhöz tartozik, aki aláírta és egy bizonyos biztonsági szintet nyújt.
Létre kell hozni hozzá egy Keystore-t, majd generálható is a signed APK. Itt kiválasztható, hogy debug vagy release formában legyen generálva. Ha kész már telepíthető is!

Layout

A Layout határozza meg az adott alkalmazás kezelőfelületének a struktúráját. Hierarchikusan épülnek fel, View és ViewGroup objektumokat tartalmaznak. A View (gyakran utalnak rá widget néven is) egy része a kijelzőnek, egy négyzet, amely valamilyen elemet tartalmaz, ez legyen egy kép, szöveg, gomb vagy bármi, amit egy alkalmazás megjelenít. A View Groups, vagyis View Csoportok pedig ezeknek a különálló View elemeknek az összefogását látják el. Mivel a layout XML formátumban van, így ebből következik, hogy egyszerre csak egy gyökér eleme lehet, tehát ha több elemre van szükség az alkalmazás felületéhez, muszáj valamilyen összefogó elemet használni, ami a ViewGroup. A ViewGroup osztálynak a leszármazottjai a layout konténerek. Ezek felelősek a felhasználói felületért, mivel ezek tartalmazzák a View-kat.


A View és ViewGroup-ok hierarchiája

Két módon hozható részre GUI elem. Vagy előre definiálva az XML fájlban, vagy pedig dinamikusan, futásidőben programkódból hozva létre. A gyakori megoldás a kettő keveréke. Előre definiált UI elemek amiket aztán futásidőben módosítunk.

Gyakori ViewGroup-ok.

Linear Layout

Ahogy a nevéből is adódik, ez egy lineáris elrendezést foglal magában. Lehet horizontális vagy vertikális az elrendezés, a lényeg, hogy a benne szereplő View elemek egymást követik. Az orientációja egyszerűen az android:orientation attribútum segítségével változtatható. Fontos momentum a Linear Layout súlyozása, vagyis a Layout Weight. Ez arra szolgál, hogy a layout minden gyerek eleme ugyanannyi vagy pedig meghatározott részt kapjanak a kijelzőből. Ha a weight-je nagyobb egy elemnek akkor nagyobb helyet kap a layoutból, ha kisebb, akkor kevesebbet.
például:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/holo_blue_bright"
android:hint="Weight:1" />
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/holo_green_light"
android:hint="Weight:1" />
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"
android:background="@android:color/holo_red_light"
android:hint="Weight:3" />
</LinearLayout>

Az orientáció vertikális, a magasságot pedig a weight-ekkel állítjuk, így a magasságot 0 dp-re kell állítani.
Ennek a kimenetele a következő:

Persze lehet horizontális is, ebben az esetben a szélességet kell 0 dp-re állítani:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="horizontal" >
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@android:color/holo_blue_bright"
android:hint="Weight:1" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@android:color/holo_green_light"
android:hint="Weight:1" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:background="@android:color/holo_red_light"
android:hint="Weight:3" />
</LinearLayout>

Ez pedig a következő kimenetelt produkálja:

Relative Layout

A Relative Layout egy olyan ViewGroup, ami, a nevéből is következtethetően, egymáshoz vagy a szülőhöz képest relatívan helyezi el a gyerekeit. Egyik a másik elem mellé, alá, fölé kerülhet, nem foglalkozva azzal, hogy milyen sorrendben jönnek egymás után a widgetek.

pl:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@+id/button"
android:background="@android:color/holo_red_light"
android:hint="TEXT VIEW" >
</TextView>

<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/button"
android:layout_centerHorizontal="true"
android:background="@android:color/holo_green_light"
android:hint="TEXT VIEW" >
</TextView>

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Button" >
</Button>

</RelativeLayout>

Ez pedig a következőként jelenik meg:

ConstraintLayout

Ez már egy érdekesebb állatfaj. Nem fogok belemenni, csak a felszínét kapargatjuk meg kicsit. A lényeg, hogy ez nem nested hierarchiára épülő layout. Responsive layout létrehozására célszerű használni. Ezzel nagyon jól használható az IDE Layout Editora is. Idővel célszerű közelebbi kapcsolatot létesíteni vele, mert manapság az egyik legfontosabb layout viszont igényel némi kompetenciát a témában. Az ismerkedéshez az IDE Layout Editorát ajánlom elsőként, aztán pedig a hivatalos dokumentációt.

RecyclerView

Ismét egy View amiről nem fogok mélyen beszélni. Amennyiben scrollozható View-ra van szükségünk, két döntés jön szóba. Magának a konténernek adunk scrollozhatóságot a ScrollView segítségével és egy ListView-ba jelenítjük meg a dolgokat. Ekkor nehéz a manipuláció, az egész lista egyszerre renderelődik, nagyszámú listaelemnél ellehetetlenítheti a használatot, ellenben egyszerű létrehozni őket.
A nehezebb, de effektívebb megoldás pedig a RecyclerView. Ennek elemei nem egyszerre renderelődnek, hanem saját adapterrel oldható meg a dolog. Ebből kifolyólag szükség van hozzá Java oldali manipulációra is. Szintén célszerű a hivatalos dokumentációt átnézni alaposan a használatához.

Attribútumok

Sok View-nak vannak saját attribútumaik, viszont vannak olyanok amik általánosak. ID minden elemhez rendelhető, erre tudunk listenert írni, ehhez képest tudjuk állítani a Relative Layout gyerekeit és a többi. Ugyan úgy a layout_height és width, és olyan ami minden view-n használható. Gyakori a "wrap content", ebben az esetben csak akkora a View, amekkora helyet a tartalma foglal, és a "match parent" is, melynél a szülő méretét veszi fel a View. Persze az onClick attribútum is elég gyakran használt.

Kezdetnek ezeket jó, ha tudjuk. Majd későbbi részekben megnézünk egy-egy komolyabb layoutot valamilyen egzakt példán keresztül.

Java oldal

Activity

Ellentétben a desktop alkalmazásokkal, a mobil felhasználás módja nem determinisztikus. Nem feltételezhetjük, hogy mindig ugyan ott kezdődnek a dolgok. Az Activity-k ennek a paradigmának a megoldására lettek létrehozva.

Az Activity-k az alkalmazás komponensek, azok a részek, amin a felhasználó interakciót hozhat létre a funkciók eléréséhez.

Minden Activity-nek külön felhasználói felületre van szüksége, amik általában kitöltik az egész kijelzőt, viszont olyan is lehet, ahol másik fölött helyezkedik el. Egy alkalmazás általában több Activity-t tartalmaz amik csak lazán kötődnek egymáshoz. Egy-egy interakció másik és másik Activity-re vezethet. Amikor elindul egy új Activity, az előtte lévő megáll, hátra rakja a rendszer, majd ha az új Activity
megkapja a lezáró metódusát vagy a felhasználó a „vissza” gombot használja az eszközön, visszatér az előtte lévő Activity-re. Amennyiben az utolsó Activity-hez ér a felhasználó, a rendszer a Launcher alkalmazást helyezi előtérbe. Valamint az alkalmazás kezdő Activity-jéhez is regisztrálni kell a launcher kategóriát, így az alkalmazás indulásakor ez az Activity fog elindulni. Ez egy klasszikus LIFO (Last In, First Out) sorozat. Az Activity élete hasonlít az Operációs rendszerben lévő processzek életéhez.

Fragment

A Fragment-ek reprezentálják egy alkalmazás részeit, viselkedéseit. A felhasználói felület részei és az Activity-ket bontják részekre. Kombinálhatunk több Fragment-et egy Activitybe, és egy Fragment is jelen lehet több Activity-ben. Lényegében a Fragment-ek moduláris részei egy Activity-nek. Saját életciklusuk, metódusaik vannak. Ha olyan helyzetbe kerülünk, hogy egyik képernyőről a másikra megfelelően sok információt kell átadni, akkor nem érdemes ezt két Activity-vel megoldani. Gyakran a dinamizálás és az erőforrás csökkentés érdekében célszerű Fragment-eket használni.

Intents és Intent Filters

Az Intent maga, mint szó, azt jelenti, hogy elszánt. Ebben az esetben az Intent az "Intent to do something" mondatot foglalja magában. Tehát valamilyen viselkedéshez kötődik az Intent.
Lényegében egy kommunikációs objektum, ami más részeket inicializál. Segítségével átadható a bundle másik komponensnek, valamint indíthatók új Activity-k, Service-k.

pl. új Activity indításra használható:

Intent intent = new Intent(this, MasodikActivity.class);
String message = "Ez az üzenet átkerül a MasodikActivity-hez";
intent.putExtra(ATADOTT_UZENET, message);
startActivity(intent);

Létezik explicit és implicit intent.
Az explicit az adott alkalmazáson belüli kommunikációhoz szükséges, míg az implicit, ha más alkalmazással szeretnénk kommunikálni.
Ahhoz, hogy egy Activity fogadni tudjon intenteket, szükséges a manifest file-ban definiálni ezeket filterként.
Például ha szeretnénk, hogy egy Activity képes legyen fogadni ACTION_SEND intentet, ahhoz ezt hozzá kell fűzni:

<activity android:name="SajatActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>

Ez után ha egy másik alkalmazás az ACTION_SEND intentet próbálja meg elküldeni akkor a SajatActivity reagálni fog rá.

Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "Ide jön az üzenet");
sendIntent.setType("text/plain");
startActivity(sendIntent);

Összegzés

Persze nem ennyi, amit tudni kell a nagy képhez, de a kezdetekhez nagyjából ezek a minimum dolgok. Észrevételeket, kérdéseket kommentben várok szeretettel. Ha továbbra is van igény, akkor folytatom a sorozatot, speciálisan egy-egy témakörre rákoncentrálva.
Addig is köszönöm szépen, hogy velem tartottatok!
Aki nem fél az angol nyelvtől és szeretne kicsit mélyebben belelátni a dolgokba, akkor a developer.android.com/guide oldal egy remek kezdés!

Azóta történt

Előzmények