Postat de la Oct 20, 2012 in Tutoriale | 0 comentarii

@uthors: Marian Perca & Octav Dospinescu

Pentru a descoperi minunata lume a aplicațiilor mobile vom începe cu un exemplu simplu în care:

  • Vom crea un nou proiect Android;
  • Vom defini layout-ul Activității într-un fișier XML;
  • Vom asimila acest layout unei Activități;
  • Vom afișa un mesaj de notificare introdus de utilizator.

Astfel, vom diseca aplicația și o vom explica pas cu pas pentru a înțelege cât mai bine modul în care lucrează platforma Android.

Crearea unui proiect

Pentru a crea un nou proiect trebuie să deschidem mediul de lucru Eclipse și să accesăm din meniul File -> Meniu -> Project… opțiunea Android Project. În fereastra care se va deschide va trebui să configurăm noul nostru proiect.

Elementele principale de care trebuie să ţinem cont atunci când completăm această fereastră sunt:

Project Name – Acesta este numele proiectului Eclipse, cât şi a directorului în care vom găsi aplicaţia noastră.

Application Name – Acesta este numele aplicaţiei care va apărea în dispozitivul mobil.

Package Name – pentru a defini numele pachetului din care vor face parte clase pe care le vom defini, vom urma aceleaşi reguli de definire a pachetelor ca în cazul unui proiect Java. Acesta trebuie să fie unic în tot sistemul Android în care este instalată aplicaţia noastră, de aceea este recomandat să folosim un nume de domeniu, în cazul nostru ro.uaic.feaa.helloworld.

Create Activity – Acesta este numele clasei exemplu care va fi generată la crearea proiectului. Aceasta va fi o subclasă a clasei Activity din Android, fiind punctul nostru de pornire în crearea aplicaţiei, deoarece acest tip de clasă reprezintă fundaţia unei aplicaţii. Putem păstra aceasta clasa generată, sau putem crea noi alta.

Min SDK Version – Această valoare indică nivelul minim API pentru care creăm aplicaţia. Este indicat să proiectăm aplicaţia noastră pentru un nivel cât mai scăzut, pentru a acoperi o plajă cât mai largă de dispozitive mobile.

Structura proiectului

Un proiect Android are la bază un sistem de directoare ierarhizate, la fel ca și un proiect Java. Cu toate acestea, particularitățile sunt unice pentru Android. Pentru a crea o aplicație trebuie să înțelegem modul în care este structurat acesta:

  • src – este directorul în care vom găsi codul Java aferent proiectului nostru;
  • gen – în acest director, Android va stoca codul generat pentru rularea proiectului;
  • assets – conține toate fișierele pe care dorim să le includem în proiect;
  • res – este un director care conține resursele aplicației precum: elemente grafice, designul aplicației sau descrierea unor elemente din aplicație. Acesta este împărțit la rândul său în mai multe directoare:
    • res/drawables/ - pentru imagini;
    • res/layout/  - pentru fișiere XML care descriu interfața utilizator;
    • res/menu/ - specificațiile XML pentru meniurile din aplicație;
    • res/values/ - pentru șiruri de caractere, matrici sau alte elemente asemănătoare;

În funcție de particularitățile proiectului, putem adăuga în acest director orice elemente de care avem nevoie în aplicație.

  • AndroidManifest.xmlacest fișier XML conține descrierea aplicației, ce activități, servicii include sau ce permisiuni necesită aplicația pentru a rula.

În momentul în care compilăm proiectul prin intermediul Eclipse sau orice alt IDE[1], fișierele rezultate în urma acestei acțiuni le vom găsi în directorul bin/ din rădăcina proiectului nostru, după cum urmează:

  • bin/namespace/clasele Java compilate, unde namespace reprezintă numele pachetului specificat la crearea proiectului;
  • bin/classes.dexreprezintă un fișier executabil creat din clasele compilate;
  • bin/resources.ap_acest fișier este o arhivă a resurselor aplicației noastre;
  • bin/NumeAplicatie.apkaceast fișier este aplicația noastră, care va fi instalată pe dispozitivul mobil.

Crearea interfeței utilizator

În acest moment am creat proiectul HelloWorld, iar Android ne-a creat toate fișierele necesare pentru a putea începe să construim aplicația noastră. În continuare, ne propunem să creăm o aplicație care să conțină un câmp în care putem scrie orice dorim, iar acest text să fie afișat ca un mesaj de notificare când apăsăm butonul “Afișează notificare”. Pentru a realiza toate acestea, trebuie să modificăm layoutul aplicației și să introducem linii de cod în activitatea generată.

Să analizăm un pic structura fișierului generat la crearea proiectului și anume HelloWord.java

public class HelloWorld extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

După cum putem observa această clasă extinde clasa Activity și suprascrie o metodă din aceasta: onCreate().  Această metodă este apelată la pornirea Activității. Ceea ce ne propunem pentru început este modificarea designului aplicației, iar pentru a realiza aceast lucru, avem la dispoziție două metode:

  • declararea elementelor din interfață într-un fișier XML;
  • instanțierea elementelor din interfață în momentul rulării aplicației. Pentru aceasta va trebui să manipulăm elementele într-un mod programatic (cod Java).

Platforma Android ne oferă o mare flexibilitate în construirea interfeței utilizator. Putem folosi doar una din cele două metode sau le putem combina pentru a realiza exact ceea ce ne dorim. Spre exemplu, putem defini structura de bază a interfeței în fișierul XML, iar apoi putem adăuga cod în aplicația noastră pentru a adăuga noi obiecte, sau pentru a le modifica pe cele deja definite în fişierul XML.

Avantajul definirii elementelor unei interfețe prin metoda XML este separarea interfeței de codul care controlează elementele definite. Asta înseamnă că implementarea aplicaţiei este mult mai logică şi mai uşor de urmat, ori de câte ori va fi nevoie să modificăm un element din interfaţă nu va trebui decât să îi ajustăm proprietăţile din fişierul XML. Un lucru foarte la îndemână în platforma Android este sintaxa XML pentru definirea elementelor UI[2]. Acestea respectă aceleaşi reguli de definire ca şi clasele sau metodele din cod, unde numele clasei corespunde cu numele obiectului iar numele metodei corespunde cu atributele pe care le acceptă obiectul.

În cadrul capitolelor ce urmează vom prezenta exemple de implementări pentru ambele metode, dar în principal vom folosi fișierele XML pentru a introduce şi aranja elementele de care avem nevoie în aplicaţiile noastre.

În cadrul platformei Android pentru a defini interfața utilizator pentru o Activitate trebuie să folosim o structură care să conţină noduri de tip ViewGroup sau simple View-uri. Aceasta poate fi cât de complexă sau simplă dorim şi o putem crea folosim widget-uri şi layout-uri predefinite sau putem crea noi înșine view-uri particularizate.

Pentru a atribui un asemenea layout unei activități trebuie să inserăm următoarea linie de cod în metoda onCreate():

setContentView(R.layout.<em>main</em>);

În sistemul Android aceste fişiere XML sunt percepute ca fiind resurse ale aplicației, aşadar le vom găsi în directorul res/layout în cadrul proiectului nostru. Fiecare fişier de acest gen conţine o structură ierarhică de widget-uri şi containere care descriu modul în care va arăta un anumit ecran din aplicaţia noastră. XML se aseamănă destul de mult cu HTML deoarece structura sa este ușor de urmărit și înțeles.

Fișierul care conține layout-ul nostru se numește main.xml și este structurat astfel:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="right"
    android:padding="5dip">
	<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="@string/titlu_aplicatie"
	    android:textSize="16dip"
	    android:paddingBottom="10dip"/>

    <EditText
    	android:id="@+id/notificare"
    	android:layout_width="fill_parent"
    	android:layout_height="wrap_content"
    	android:hint="@string/hint_notificare" />

    <Button
    	android:id="@+id/afiseaza_mesaj"
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:text="@string/text_afiseaza_notificare" />
</LinearLayout>

În acest prim proiect s-a utilizat un layout de tip liniar. Acesta poziționează toate elementele pe care le conține în linie sau pe coloană. Pentru a defini orientarea trebuie îi adăugăm atributul android:orientation. Acesta poate primi 2 valori: vertical pentru a aranja elementele în coloană și horizontal pentru a aranja elementele în linie. Dorim ca layout-ul nostru să se extindă pe întregul ecran, astfel vom adăuga atributele android:layout_width și android:layout_height cu valoarea fill_parent.

După cum putem observa, elementul LiniarLayout conține trei elemente TextView, EditText și Button, acestea fiind obiectele cu care utilizatorul va interacționa. Cu ajutorul elementului TextView vom afișa un titlu; de obicei cu ajutorul elementelor de acest gen vom afișa porțiuni informative de text; EditText este special creat pentru text editabil, astfel încât vom plasa un element de acest tip în layoutul nostru pentru a capta textul care va fi afișat în mesajul de notificare; Button reprezintă butonul care va declanșa afișarea mesajului de notificare.

Elementele EditText și Button au un atribut mai special și anume android:id. Multe dintre widget-urile, containerele sau obiectele pe care le utilizăm în crearea layout-ului XML nu vor fi manipulate din codul Java, spre exemplu elementele de tip TextView care nu reprezintă altceva decât text static. Nu va fi necesar decât să le poziționăm prin intermediul atributelor din fișierul XML. Pentru toate celelalte elemente pe care dorim să le utilizăm în fișierele Java va trebui să le adăugăm atributul android:id. Există o convenție pentru definirea acestor id-uri și anume să folosim @+id/denumireId unde denumireId reprezintă numele unic pe care îl atribuim elementului. În exemplul nostru, pentru elementul EditText am utilizat atributul android:id=”@+id/notificare”, astfel încât îl putem apela din Java cu ajutorul id-ului notificare.

Lăţimea şi înălţimea pentru elementul EditText au fost stabilite cu ajutorul atributelor:

  • android:layout_width=”fill_parent” – datorită valorii fill_parent va avea aceeași lăţime ca şi elementul părinte, în cazul nostru LinearLayout care se întinde pe întreaga lățime a ecranului;
  • android:layout_height=”wrap_content” – prin acest atribut cu valoarea wrap_content definim ca înălțimea elementului să fie variabilă în funcție de textul pe care îl cuprinde. Astfel, pe măsură ce vom scrie, înălțimea se va ajusta în mod automat.

Pentru a da un aspect mai plăcut interfeței am adăugat atributele:

  • android:gravity=”right” – prin intermediul acestui atribut am aliniat toate elementele din LinearLayout la dreapta;
  • android:padding=”5dip” – cu ajutorul acestui atribut am adăugat un spațiu între marginile elementului LinearLayout și elementele care le conține.

În continuare, pentru a manipula obiectele din interfața creată, trebuie să le instanţiem în activitatea noastră: HelloWorld.java. În cele din urmă, aceasta va arăta astfel:

package ro.uaic.feaa.helloworld;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class HelloWorld extends Activity implements OnClickListener{
    /** Called when the activity is first created. */
    @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button btnNotificare = (Button)findViewById(R.id.afiseaza_mesaj);
btnNotificare.setOnClickListener(this);
}

	@Override
public void onClick(View v) {
		EditText textNotificare = (EditText)findViewById(R.id.notificare);

		Toast toast = Toast.makeText(getApplicationContext(), textNotificare.getText(), Toast.LENGTH_SHORT);
		toast.show();
	}
}

În această aplicație va trebui să afișăm un mesaj atunci când apăsăm pe butonul ”Afișează notificare”, de aceea trebuie să implementăm interfața OnClickListener pentru a putea capta evenimentul click. Din această interfața trebuie să suprascriem metoda onClick().

În metoda onCreate() vom crea o variabilă de tip Button, care va fi o referință a elementului creat în XML și pe care îl putem identifica prin id-ul atribuit: ”afiseaza_mesaj”. Pentru a realiza acest lucru vom folosi metoda (Button)findViewById(R.id.afiseaza_mesaj). După ce am creat butonul vom ”asculta” evenimentul ”click”.

În funcția onClick() vom afișa mesajul de notificare. În primul rând, va trebui să preluăm mesajul din căsuța de text afișată. Pentru aceasta, trebuie să creăm un obiect de tipul EditText care va face referire către elementul de același tip creat în XML:

EditText textNotificare = (EditText)findViewById(R.id.notificare);

Apoi, vom crea un obiect de tip Toast pe care îl vom folosi pentru a afișa mesajul nostru. Cu acest tip de obiect Toast putem crea mesaje tranzitorii, care vor apărea şi vor dispărea fără a fi nevoie de interacţiunea utilizatorului. Vom discuta mai multe aspecte despre acest tip de mesaj în capitolele următoare.

Metoda makeText() acceptă trei parametri printre care vor fi textul afișat, precum şi durata de afişare. Pentru a prelua textul din obiectul de tip EditText, avem la dispoziție metoda getText(), iar pentru a stabili timpul de afișare folosim constanta Toast.LENGTH_SHORT. Mesajul de notificare îl vom afișa folosind metoda show() a obiectului de tip Toast.

Crearea unui emulator

Deși suntem nerăbdători să rulăm aplicația noastră, trebuie mai întâi să creăm un dispozitiv virtual pe care să ruleze. În Android acesta se numește AVD –Android Virtual Device. Desigur, dacă avem un dispozitiv fizic pe care să rulăm aplicația, nu mai este necesar să crem unul virtual.

AVD reprezintă un emulator pe care îl putem particulariza alegând componentele hardware și software pe care Android le va emula. Pentru a crea un AVD, cea mai simpla metodă este utilizarea managerului AVD. Pentru a-l porni vom accesa Android SDK and AVD Manager din meniul Window al Eclipse. Alternativa este linia de comandă, folosind comanda androidcu opțiunile pe care le dorim pentru a-l particulariza.

android create avd -n <name> -t <targetID> [-<option> <value>] …

Dacă folosim AVD Manager, din fereastra care ni se va deschide vom alege New… pentru a crea un AVD nou:

În fereastra cu detalii ni se va cere să completăm numele pe care dorim să îl atribuim AVD-ului, nivelul API (Target) pentru care va fi creat, dimensiunea SD cardului, dimensiunea ecranului şi o listă în care vom putea specifica suportul hardware pe care îl va oferi emulatorul.

Putem crea oricâte AVD-uri avem nevoie, în funcție de tipul de dispozitiv mobil pe care vrem să-l emulăm. Pentru a testa aplicația cât mai bine trebuie să creăm câte un AVD pentru fiecare dispozitiv din piața noastră țintă (diferite dimensiuni ale ecranului și platforme). În configurarea AVD-ului trebuie să acordăm o mare importanță nivelului API, deoarece nu trebuie să fie mai mic decât cel specificat la crearea proiectului Android. Trebuie să ţinem cont de faptul că aplicaţia noastră nu va putea rula pe un dispozitiv cu un nivel API mai mic. Ideal este ca aplicația să rule pe toate dispozitivele mobile indiferent de platformă, dimensiunea ecranului sau caracteristicile hardware. Acest lucru este dificil de realizat întrucât periodic apar noi versiuni ale platformei Android, telefoane de dimensiuni diferite. Soluția ar fi să testăm aplicația pe cât mai multe emulatoare, astfel încât utilizatorii să nu întâmpine probleme în rularea aplicației, indiferent de dispozitivul mobil pe care îl folosesc.

Cu toate acestea, testarea aplicaţiei pe un AVD nu poate înlocui testarea pe un dispozitiv fizic. Emulatoarele ne permit să testăm aplicația noastră pe o gamă largă de dispozitive, chiar și pe cele care încă nu există pe piață. Totuși, aplicația ar trebui testată pe cel puțin un dispozitiv Android, deoarece cele două nu se pot compara, atât din privința vitezei de răspuns cât și a senzației oferite de interfața utilizator.

Dacă suntem obişnuiţi deja cu AVD-urile, atunci ştim cât de greu pot porni. Cei de la Android au venit cu o nouă facilitate pentru a îmbunătăți timpul de pornire al emulatorului, şi anume Snapshot. Dacă bifăm această opţiune, atunci când se creează un nou AVD, Android va realiza o imagine a emulatorul atunci când îl vom închide. Astfel, atunci când dorim să pornim emulatorul se va deschide aproape instantaneu pe baza imaginii create.

După ce am creat emulatorul nu ne rămâne decât să rulăm aplicația. Pentru a realiza aceasta din meniul Run > Run as, vom alege Android Application. Aplicația va trebui să arate ca cea din figura de mai jos:

(c) Marian Perca & Octav Dospinescu