Sunteți pe pagina 1din 180

AIDM – Aplicații Informatice pentru Dispozitive Mobile

Cui se adresează – studenților CTI anul 4

Cunoștințe necesare:
 fundamente Java: clase, variabile, structuri de control
 ce este API (Application Programming Interface)
 ce este IDE (Integrated Development Environment)
 fundamente XML

1
Cuprins
Mobile app ...............................................................................5
IDE ...........................................................................................6
Android ....................................................................................8
Software necesar ....................................................................12
Tipuri de aplicații mobile ......................................................15
Android Studio.......................................................................16
Configurarea Android Studio ................................................20
Android SDK .........................................................................22
Crearea unui proiect în AndroidStudio ..................................25
Rulare .....................................................................................30
Etapele compilării ..................................................................41
Procesul de realizarea a unei aplicații mobile .......................42

2
Structura unui proiect AndroidStudio....................................45
Componentele unei Mobile app .............................................51
Activity ..................................................................................52
Exemplu – Curs1 ...................................................................60
Exemplu – Buton ...................................................................70
Conectarea la Internet ............................................................79
Permisiuni ..............................................................................83
Fire de execuție ......................................................................85
Task asincron .........................................................................87
Exemplu – InternetConnection ..............................................88
Exemplu – RSSExample........................................................96
Exemplu – OperatoriCuIntregi ............................................113
Baze de date .........................................................................123

3
Exemplu - BazaDate ............................................................130
Exemplu – FileIO ................................................................152
Componente aplicații mobile ...............................................135
Exemplu FereastraSecundara ..............................................159
Android Studio Shortcuts ....................................................164

4
Mobile app
 specifice pentru o platformă și pentru un tip de dispozitiv
mobil,
 pot fi comerciale sau free,
 GUI orientat pe evenimente cu utilizatorul,
 folosesc camera foto, geolocația GPS, accelerometru,
compas, sistemul de fișiere, notificări (text, sunet,
vibrație), memorie.

SO pentru mobile: iOS, Android, Balckberry, Windows,


webOS, SymbianOS, Obada.

5
IDE
 AndroidStudio,
 Eclipse,
 PhoneGap (cross platform – același cod poate fi compilat
pentru iOS, Android),
 Xamarine,
 Visual Studio Community (cod în HTML5 + CSS +
JavaScript și poate fi compilat pentru mai multe SO),
 etc.

6
Avantaje Mobile App:
 Rulează de obicei mai repede pe Mobile app decât într-o
pagină web,
 Pot fi disponibile off-line,

Dezavantaje Mobile App:


 O aplicație bussiness ar trebui să fie disponibilă pe mai
multe SO.
 accesul la market este controlat de o firmă (Apple,
Android),
 upgrade-ul se face prin intermediul market (download and
install).
 Trebuie update periodic și mentenanță tehnică.

7
Android
Android este dezvoltat de Google (din 2008, prin intermediul
consorțiului comercial Open Handset Alliance), pentru
dispozitivele mobile (smartphone, tablete, reader, auto, tv,
wear).
Cuprinde:
– sistem de operare,
– middleware,
– aplicaţii de bază (client de e-mail, program de SMS,
calendar, hărţi, browser, agendă pentru date de contact,
etc.).

http://developer.android.com/index.html

8
Android este un mediu dinamic – număr mare de versiuni.
API se schimbă constat: pentru fixarea unor bug-uri,
îmbunătățirea performanțelor, îmbunătățiri la nivelul bateriei,
securității, accesibilității, etc.
https://developer.android.com/about/dashboards/index.html

Începând cu versiunea 5.0 au fost introduși diferiți senzori


(exemplu, senzori de mișcare, senzori pentru ritmul cardiac al
persoanei care atinge dispozitivul).

9
10
Arhitectura SO Android:
 aplicații
 API framework – comunică cu serviciile sistemului
(Windows manager, Notification manager) și cu serviciile
media, pentru accesul la hardware.
 HAL – definește o interfață standard astfel încât
producătorii de dispozitive mobile să poată dezvolta
drivere la nivel low-level, fără a afecta funcționalitățile la
nivel high-level.
 Linux kernel – permite dezvoltarea driverelor ca și în
Linux. Sunt disponibile mai multe versiuni de kernel
https://source.android.com/source/building-kernels.html.

11
Software necesar

 Java JDK – pentru compilarea claselor Java


http://www.oracle.com/technetwork/java/javase/downloads/in
dex.html
Trebuie setată o variabilă de mediu către SDK: System
Variable – Name: Java_Home, Value: c:\Program
Files\Java\jdk1. \
Se recomandă folosirea ultimei versiuni de Java disponibile
(pentru a afla versiunea instalată în calculator –
cmd: java –version).

 Aplicaţiile pentru Android se bazează pe limbajul de


programare Java.

12
 Android Studio – este un IDE oficial susținut de Google
bazat pe platforma IntelliJ IDEA (creat de JetBrains) în
versiunea lui free (Community Edition) - pentru compilarea
în pachete Android și rulare. Pot fi instalate mai multe
versiuni simultan)
http://developer.android.com/sdk/index.html

 API – documentaţia claselor Android


http://developer.android.com/reference/classes.html

 Cel puțin un dispozitiv mobil cu Android (diferă


producătorul, dimensiunea ecranului, rezoluția). Este indicat
ca testarea să se facă pe dispozitive cât mai multe și mai
variate.

13
 Emulator Android (se instalează odată cu Android Studio).
La 8Gb de Ram se recomanda 2Gb pentru emulator.
Dimensiunea memoriei Ram influențează câte emulatoare
pot rula simultan. Fiecare emulator consumă între 1.5 și
2Gb.
 Intel emulator Accelerator – HAXM – crește viteza
emulatorului.
 Verificarea periodică pentru Updates.
 Pentru aplicații noi versiunea de Android SDK minim
cerută este API level 15.
 Android SDK Build Tool (Android Studio
Manager/Android SDK/SDK Tools) – pot fi instalate
simultan mai multe versiuni.

14
Tipuri de aplicații mobile
 Aplicații native – create pentru a fi folosite doar pe
dispozitive mobile (smartphone, tabletă). Sunt create
de obicei pentru un număr restrâns de dispozitive.
Folosesc tehnologii SDK. Au nevoie de instalare și
update de pe store.
 Aplicații mobile web – accesează un server web pentru
comunicații de date folosind un browser. Folosesc
tehnologii web (HTML, CSS, Asp.net, Java, Php).
Sunt cross-platform. Nu au nevoie de instalare, iar
update-ul este generalizat.
 Aplicații hibride – sunt o combinație a celor două de
mai sus și pot rula online sau offline. Sunt scrise
folosind tehnologii web (HTML5, CSS).

15
Android Studio
– IDE care cuprinde:
o Editor de cod - code template, code completion, code
highlith
o Editor de UI – manager de poziționare, drag-and-drop
o Net tools – urmărirea performanțelor, grad de utilizare,
versiuni
o Bazat pe Gradle (sistem de creare automată a
aplicațiilor bazat pe plugin-uri – compilare, rulare
instantanee, debug pentru Java și C++, testare. Este
open source).
o Gradle – creează multiple aplicații folosind același
proiect.
o Dispozitive virtuale
o Android SDK Tools
o Android Platform-tools
16
o Folosește GitHub – sistem de control al versiunilor
(păstrează un istoric al modificărilor într-un repository,
asigură colaborare între programatori, upload-
download unei noi versiuni). GitHub.com oferă spațiu
pentru păstrarea proiectelor în diferite versiuni. Meniul
VCS – Version Control System.
o Import de exemple de la Google în fereastra inițială.

17
o Manager TODO – se pot introduce comentarii cu
TODO care apoi pot fi vizualizate în fereastra TODO.
Exemplu de TODO în fișierul xml
<!-- TODO de adaugat un nou item -->
Exemplu de TODO în fișierul java
// TODO de adaugat functia ptr ActionBar

18
19
Configurarea Android Studio
 File-Settings – setează comportamentul și modul de
vizualizarea al IDE-ului.
 Appearance & Behaviour
 Keymap – schimbă comportamentul shortcut pentru
taste
 Editor – schimbă comportamentul pentru editorul de
cod (line numbers, methods separators, Font)

20
21
Android SDK
(Software Development Kit)
 compilează codul unei aplicaţii într-un pachet Android, care
este o arhivă cu extensia .apk, care apoi poate fi instalată pe
orice dispozitiv care rulează Android.
 Include un emulator de dispozitiv mobil virtual
AVD (Android Virtual Device) care rulează pe computer.
Emulatorul permite dezvoltarea şi testarea aplicaţiilor
Android fără a fi nevoie de dispozitivul fizic. Interacţiunea
cu emulatorul se realizează prin mouse în loc de
touchscreen-ul dispozitivului şi taste în loc de butoane.

 Android SDK are un manager prin care se pot instala


documentaţii şi alte pachete.

22
 Din Android SDK Manager se instalează o versiune de
Android.

23
 Trebuiesc instalate minim:
o Android SDK Tools
o Android SDK Platform-tools
o Android SDK Build-tools
o Emulator system (exemplu, Google APIs Intel x86
Atom_64 System Image)

În folderul Android X.X minim trebuiesc instalate:


o Android SDK Platform
o Sources for Android

24
Crearea unui proiect în AndroidStudio
 În Android Studio - File – New – New Project
 Project Name - este numele proiectului. Numele proiectului
dă și numele pachetului de clase java și numele aplicației
mobile.
 Company domain – un nume care va fi adăugat la numele
pachetului în care va fi salvat proiectul. Are aceeaşi
structură ca la Java. Folderul src – conţine fişierele sursă
java. Numele pachetului declarat iniţial trebuie să fie format
din cel puţin 2 module separate prin punct. Dacă se dorește
ca aplicația să fie listată pe Market, atunci acest nume de
pachet trebuie să fie unic.
 Package name – poate fi schimbat și setat identic la mai
multe aplicații pentru a crea un singur pachet.

25
 Build Target – este versiunea de Android SDK în care va fi
compilat proiectul.
 Minimum SDK – indică cea mai veche versiune pe care va
rula aplicația. Help me choose – afișează o statistică a
versiunilor de Android și utilizarea lor. Informații
suplimentare la
https://developer.android.com/about/dash
boards/index.html
 Application Name – numele aplicaţiei care va apare pe
dispozitivul mobil
 Trebuie selectate dispozitivele pentru care este destinată
aplicația în fereastra Target Android Devices.
 În fereastra Add an Activity to Mobile se alege un șablon de
activitate pentru interfața grafică a aplicației. De obicei se

26
alege Empty Activity. Numele Activity dă numele clasei
java și a fișierului Xml pentru layout (manager grafic).
 În fereastra de vizualizare a proiectului nu se vede implicit
structura de directoare de pe disk a proiectului. Aceasta se
activează cu selectarea opțiunii view din Android în Project.

Main Activity – se creează automat clasa de bază, subclasă a


clasei AppCompatActivity, care va rula aplicaţia. În această
clasă este rescrisă metoda onCreate(...) unde trebuie făcute
toate iniţializările, inclusiv interfaţa grafică.

27
28
Setarea minSDK
 pentru nivelul minim de SDK în care aplicația va funcționa.
 Setarea unui SDK foarte vechi garantează funcționarea pe
dispozitive mai vechi, dar vine cu dezavantaje: crearea de
versiuni compilate pentru diferite API (unele deprecated),
lipsa unor funcționalități (ex., widget pentru home screen,
Android Tv).

Setarea targetSDK
 Arată versiunea în care s-a făcut testarea.

29
Rulare
 Pe un dispozitiv mobil – se conectează dispozitivul prin
Usb la dispozitivul pe care se dezvoltă. Apoi, în Android
Studio se dă Run și se alege dispozitivul mobil din
fereastra Select Deployment Target. Pentru debug și
rulare este nevoie de instalarea pe Windows a unui driver
ADB (Android Debug Bridge) pentru unele dispozitive
conectate prin USB. Se verifică în Control Panel, Device
Manager. Drivere pot fi găsite la
https://developer.android.com/studio/ru
n/oem-usb.html#Drivers
Pe dispozitiv se deschid Settings – About Phone- Build –
se dă click de mai multe ori până apare mesajul de
înregistrare ca Developer. Astfel, apare în Setting,
opțiunea Developer Options. Se bifează opțiunea USB
Debugging Feature. Apoi în Android Studio în tabul
30
Android Devices apare dispozitivul listat. Pentru a nu mai
folosi dispozitivul pentru testare se selectează în dispozitiv
Settings – Developer Options – Revoke USB Debugging
Authorizations.

31
 Pe un emulator -
1. Se lansează Android Virtual Device Manager din
meniul Tools > Android > AVD Manager sau iconița

.
2. Se alege Create Virtual Device în fereastra Your
Virtual Devices.

32
3. Se alege un dispozitiv mobil în fereastra Select
Hardware.

33
4. Se alege imaginea dorită pentru AVD în fereastra
System Image. Dacă nu există o imagine sistem dorită,
aceasta se poate downloada. Se pot schimba
dimensiunea ecranului și rezoluția, nivelul API,
orientarea, camera, network, ram, heap, enable
keyboard. Dimensiunea emulatorului depinde de ecran.
5. Se rulează aplicația din Android Studio cu Run . În
fereastra Select Deployment Target se alege
emulatorul dorit.
 Pornirea Emulatorului poate dura câteva minute.
 Pentru pornirea emulatorului, în BIOS trebuie aleasă
opțiunea Virtual Technology.

34
 Pe un emulator rularea unui fișier apk-
Se verifică dacă este instalat Android SDK Platform-Tools în
meniul Tools—Android—SDK Manager.

35
AVD Manager – permite pornirea dispozitivelor create cu
Start.
Rularea prin emulator are avantajul că permite testarea pe mai
multe tipuri de dispozitive, fără a le avea fizic.
Pentru pc-urile cu procesoare Intel, pentru a crește viteza de
execuție trebuie instalat Intel HAXM. Emulatorul x86 se
bazează pe un driver special numit HAXM care permite
virtualizare hardware.
Pentru instalarea HAXM se deschide meniul Tools-Android-
SDK Manager-tabul SDK Tools – se verifică să fie în listă. În
arborele de fișiere trebuie căutat un fișier IntelHAXM.exe.
pentru a instala emulatorul.
Dimensiunea ferestrei cu emulatorul poate fi modificată.
Unele au și o bară cu unelte pentru controlul dispozitivului
emulat (Back, Home, Overview, Rotate, Camera, Extendet
Controls..., Phone, Location).
36
37
38
Alternativa emulatoarelor puse la dispoziție de Android
Studio sunt cele din aplicația Genymotion, Andy, Bluestacks,
Droid4x, Koplayer, Memu, Nox (sunt mai rapide sau
dedicate, exemplu jocuri).

39
40
Etapele compilării
APK –Android Package (o formă specială de arhivă zip)
ADB – Android Debug Bridge

Gradle Jar
signer ADB
Android  Byte code
build  Resources Install on
Project sign
 Manifest device

APK

41
Procesul de realizarea a unei aplicații mobile
 Proiectare (design) –
o fluxul de ecrane, fără detalii și fără specificații de
acțiuni (de exemplu, ce se întâmplă când dau click pe o
component grafică, ce informație se dorește să se
afișeze, ce se va calcula, ce se întâmplă când schimb
fereastra),
o task-uri cheie.
 Prototip (detalii) –
o acțiuni (cele din specificații),
o funcții contextuale (copy, paste, cut),
o baze de date,
o securitate
o imagini/icon-uri (sugestive), animații, manager de
afișare (layout manager potrivit pentru unul sau mai

42
multe tipuri de dispozitive mobile). Prototipul de GUI
poate fi făcut pe hârtie (imagini statice sau dinamice se
fac mai multe poze statice care se combină cu o
aplicație de stop-motion, ex. PicPac, StopMotionPro,
DragonFrame, MaonkeyJam) sau printr-o aplicație (ex.
Flinto on-line).
 Dezvoltare – implementarea prototipului prin cod.
 Produs final (supus testării) –
o Testarea funcțională (se verifică funcționalitatea task-
urilor) – compatibilitate (pe diferite dispozitive
mobile), interfața grafică (meniuri, componente
grafice, setări, flux de navigare, istoric, bookmarks),
servicii (online/offline), ergonomie (ușor de folosit,
intuitivă), resurse de low level (încărcarea memoriei,
baze de date locale), performanțe (2G, 3G, 4G, Wifi,

43
consum baterie), instalare/dezinstalare, operațional
(backup și recovery), securitate, internaționalizare
(diferite limbi și alfabete).
o Testarea hardware – procesor, memorie
(funcționalitate), ecran cu rezoluție și dimensiune,
camera, bluetooth, wifi, hard/virtual keypad, SO,
operator de telefonie mobilă (GSM, CDMA, LTE),
producător (Samsung, Nokia, Apple, HTC, etc.).
o Testarea manuală/automată
o Testarea pe dispozitive reale (costisitoare)/emulate
(lipsește elementul surpriză dat de imperfecțiuni sau
condiții de mediu)/mixtă.
o Testarea folosind aplicații dedicate (MobiReady,
SIGOS Mobile Testing, Responsivepx,
cloudcomputing).

44
Structura unui proiect AndroidStudio
 Fișierul build.gradle – specific proiectului –
configurează Gradle build tool. Are 3 componente:
 buildscript (configurează codul pentru build),
 com.android.application (plugin-ul care
va fi folosit),
 android (configurează parametrii pentru aplicație).
 Fișierul build.gradle – specific Module: app – conține
setări ale versiunilor de Android
 Fișierul local.properties – conține setări pentru
configurarea proiectului. Linia cu sdk.dir conține calea
către Android SDK, specifică fiecărui proiect. Atunci
când se mută un proiect de pe un calculator pe altul,
această linie se șterge și va fi generată la deschiderea
noului proiect.

45
 Directoarele .gradle și .idea conțin configurații despre
mediul de dezvoltare și pot fi ignorate.
 Directorul .build conține fișiere generate de Android
Studio folosite în procesul de lucru cu pachetele.
 Directorul .app conține proiectul propriu-zis.
Reprezintă un modul. O aplicație poate avea mai multe
module.
 Directorul .app.build conține fișiere generate automat.
 Directorul .app.libs conține aplicația executabilă sub
formă de fișier .jar.
 Fișierul .app.build.gradle conține configurația pentru
versiunea de SDK, dependențe, compilator.
 Fișierul .app.proguard-rules.pro – este folosit pentru a
minimiza pachetul aplicației executabile și pentru a

46
face mai grea decompilarea (a obține sursele din
executabile).
 Fișierul .app.main.AndroidManifest.xml – memorează
activitățile, serviciile și alte componente ale aplicației.
 Directorul .app.src.main.res conține resurse (imagini,
icon). Subdirectoare
o .res/values – fișiere XML care conțin valori (de
exemplu, șiruri de caractere, numerice)
o res/values/strings.xml – fișier care definește șiruri
de caractere care pot fi folosite în aplicație sau în
alte fișiere din res. Pot fi referite prin:
 în Java: R.string.string_name
 în XML: @string/string_name

47
o .res/values/colors.xml – fișiere XML care definește
liste de culori (exemplu, <color
name="translucent_red">#80ff0000</color>)
 în Java: R.color.color_name
 în XML: @[package:]color/color_name
o res/values/arrays.xml - definește vectori de valori
(șiruri de caractere, culori) care sunt folosite în mai
multe locuri în proiect. Apelul se face astfel:
 în Java: R.array.array_name
 în XML: @[package:]array.array_name
Exemplu de fișier arrays.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="tari">
<item>Romania </item>
<item>Grecia</item>
<item>Franta</item>

48
</array>
</resources>

o .res/drawable – fișiere de tip imagine (ex. Bmp)


o .res/layouts – fișiere xml pentru managementul
poziționării componentelor grafice în ferestre.
o .res/mipmap – fișiere imagine pentru icon-uri
o .res/menu – fișiere XML care definesc meniuri
o .res/animator – fișiere XML cu proprietățile
animațiilor
 Directorul .app.main.java – fișiere java
 Directoarele .app.src.AndroidTest (teste specifice) și
.app.sec.test (teste unitare)
 R.class – este generată la compilare și conține
constante care identifică dinamic diferite componente
din directorul res.
49
 Aplicația executabilă se găsește în directorul
.app.build.outputs.apk

50
Componentele unei Mobile app
O aplicație este formată din mai multe componente care sunt
interconectate între ele și cu framework-ul Android.
Sunt 4 tipuri de componente înregistrate în Manifest:
1. Activity
2. Service
3. Broadcast receiver
4. Content provider

51
Activity
 Crează o fereastră bazată pe evenimente (interacțiunea cu
utilizatorul și cu sistemul).
 Activity sunt scrise in Java și extind clasa Activity.
 aplicația poate avea mai multe activități care sunt văzute
de utilizator ca ferestre înlănțuite.
 Fereastra principală este cea cu care pornește inițial
aplicația.
 Activitățile sunt menținute de sistem într-o stivă pentru a
asigura contextul pentru utilizator. Cu butonul Back,
sistemul revine la activitatea anterioară din stivă.
 Fiecare Activity are un layout (șablon de poziționare a
componentelor grafice) memorat în fișierul activity...xml
 O fereastră poate avea unul sau mai multe componente -
View sau containere - ViewGroup.
52
 View – o zonă dreptunghiulară pe ecran care produce și
tratează evenimente.
 View sunt specificate tot în fișierul activity...xml

53
Setările pentru layout-ul
activităților sunt în fișiere
xml organizate în directorul
app.src.main.res.layout.
Acestea pot fi vizualizate în
mod Text sau Design.

54
În fișierul principal java avem codul:
protected void onCreate(Bundle
savedInstanceState) {
setContentView(R.layout.activity_main);

Metoda setContentView convertește resursele din fișierul xml


layout într-o ierarhie de obiecte vizuale, în memorie. Clasa R
este statică și este creată implicit de mediu.
Aceste obiecte pot fi modificate prin metode în codul Java.

55
Componente grafice –View
 TextView
 EditText
 ImageView
 Button, RadioButton, CheckButton

Lista componente
https://developer.android.com/reference/android/widget/pa
ckage-summary.html

56
Containere grafice – ViewGroup
 ConstraintLayout
 RelativeLayout
 LinearLayout
 FrameLayout
 ScrollView

57
Proprietăți xml pentru componente grafice
 android:text ="text" – textul care va apare într-o
componentă
 android:layout_width="200dp" (exprimată în „density
independent” pixeli) sau "wrap_content" (micșorată să
cuprindă întreg conținutul) sau "match_parent" (mărită la
dimensiunea componentei părinte) – lățimea unei
componente
 android:layout_height="300dp"– înălțimea
 android:padding – spațiul de jur împrejurul unei
componente în interiorul marginilor acesteia
 android:layout_margin – spațiul de jur împrejurul unei
componente în exteriorul marginilor acesteia

58
 android:textSize=”20sp” (exprimată în scale-independent
pixels care depind de dimensiunea fontului aleasă de
utilizator).
 android:background="@color/colorPrimary"

59
Exemplu – ClasaObiecte
Etapa 1- Aplicație care afișează trei etichete într-o fereastră.
Are declarată clasa ClasaVariabile.java cu 4 date membre
(intreg, String, boolean și float) și 2 constructori (fără
argumente și cu toate argumentele).
public class Variabile {
int i;
String s;
boolean b;
float f;

Variabile(){
i=10;
s="Un sir de caractere";
b=true;
f=10.45f;
}
Variabile(int t, String s, boolean b, float f){
this.i=i;

60
this.s=s;
this.b=b;
this.f=f;
}
public String toStrig(){
return "Datele membre =
\n\t\t"+i+"\n\t\t"+s+"\n\t\t"+b+"\n\t\t"+f+"\n";
}
}

Se creează cu Drag-and-drop cele trei etichete. Se


inițializează textele inițiale de afișat. Fișierul creat este
activity_main.xml. Codul creat automat de AndroidStudio
este:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/and
roid"
xmlns:app="http://schemas.android.com/apk/res-

61
auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"

tools:context="devicesscreens.com.example.clasaobiect
e.MainActivity">

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Instante - valori"

app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.051"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.103" />

62
<TextView
android:id="@+id/textView2"
android:layout_width="186dp"
android:layout_height="158dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"

android:background="@android:color/holo_blue_light"
android:text=" instanta 1"
android:textSize="20sp"

app:layout_constraintStart_toEndOf="@+id/textView1"

app:layout_constraintTop_toBottomOf="@+id/textView1"
/>

<TextView
android:id="@+id/textView3"
android:layout_width="184dp"
android:layout_height="150dp"
android:layout_marginTop="24dp"
63
android:background="@android:color/holo_green_light"
android:text="instanta 2"
android:textSize="20sp"

app:layout_constraintStart_toStartOf="@+id/textView2"

app:layout_constraintTop_toBottomOf="@+id/textView2"
/>

</android.support.constraint.ConstraintLayout>

64
Etapa 2 - se inițializează variabilele v1 și v2 ale clasei
Variabile folosind cei 2 constructori și conținutul acestora
este afișat în fereastra principală a aplicației.
65
AndroidStudio ajută cu importul de clase (Alt+Enter – și
importă implicit clasele de care este nevoie).
Codul va fi completat în fișierul MainActivity.java

public class MainActivity extends AppCompatActivity {


ClasaVariabile v1,v2;
TextView textView2, textView3;

@Override
protected void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
v1=new ClasaVariabile();
v2=new ClasaVariabile(55,"un sir", false,
55.55f);
textView2 = (TextView)
findViewById(R.id.textView2);
textView3 = (TextView)

66
findViewById(R.id.textView3);
textView2.setText(v1.toStrig());
textView3.setText(v2.toStrig());
}
}

67
68
android:id="@+id/textView2" – este un identificator
numeric folosit pentru a localiza componenta. Pentru
programator se folosește un descriptiv care începe cu @, ceea
ce arată compilatorului să nu trateze ca un string. = arată
compilatorului că trebuie să creeze un id dacă încă nu există.

În fișierul java pentru a utiliza componenta respectivă se


folosește instrucțiunea:
textView2=(TextView)findViewById(R.id.textView2);

69
Exemplu – Buton
Se creează o clasă Persoana care are ca date membre nume,
prenume și dataNastere (de tip Date care a fost formatată).
public class Persoana {
String nume, prenume;
Date dataNastere;
static SimpleDateFormat formatDate=new
SimpleDateFormat("dd/MM/yyyy");

Persoana(){
nume="Popescu";
prenume="Ion";
dataNastere= new Date();
}

Persoana(String nune, String prenume, Date


dataNastere){
this.nume=nune;
this.prenume=prenume;
this.dataNastere=dataNastere;
70
}
public String toString(){
return nume+" "+prenume+" nascut pe
"+formatDate.format(dataNastere);
}
}

Se mai creează și clasa GrupaStudenti care are ca date


membre identificator, specializare și o listă cu Persoane
(ArrayList).
public class GrupaStudenti {
String identificator,specializare;
ArrayList<Persoana> lista;

GrupaStudenti(String id, String sp, int nr){


identificator=id;
specializare=sp;
lista= new ArrayList<Persoana>(nr);
}

71
public String toString(){
StringBuffer sirDeAfisat=new StringBuffer();
sirDeAfisat.append(identificator+" -
"+specializare+"\n");
for(Persoana p:lista) {
sirDeAfisat.append(" ");
sirDeAfisat.append(p);
sirDeAfisat.append("\n");
}
return sirDeAfisat.toString();
}
}

În fereastra principală se crează un buton la a cărui acțiune


vor fi afișate într-o eticheta 2 instanțe ale clasei
GrupaStudenti.

72
Tot în fereastra principală se mai adaugă un grup cu 2
butoane radio la a căror acțiune se afișează pe rând câte una
din cele 2 instanțe ale clasei GrupaStudenti.
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true">

<Button
android:text="CTI+AIA"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:id="@+id/button"
android:onClick="metodaButon"/>

<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
73
android:orientation="horizontal">

<RadioButton
android:text="CTI"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioButton1"
android:layout_weight="1"
android:onClick="metodaRadioButton"/>

<RadioButton
android:text="AIA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioButton2"
android:layout_weight="1"
android:onClick="metodaRadioButton"/>
</RadioGroup>

<TextView
android:text="nimic"
74
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView" />

</LinearLayout>

Crearea instanțelor și tratarea evenimentelor pe butoane se


realizează în fișierul java.
public class MainActivity extends AppCompatActivity {
TextView deAfisat;
Button b;
RadioButton b1,b2;
GrupaStudenti g1,g2;

void setGrupeStudenti(){
try {
g1 = new GrupaStudenti("22C41", "CTI", 3);
g1.lista.add(new Persoana("Ionescu",
"Vasile",formatDate.parse("05/10/1980")));
g1.lista.add(new Persoana("Popescu",
75
"Maria",formatDate.parse("15/3/1979")));
g1.lista.add(new Persoana("Vasilescu",
"Petru",formatDate.parse("22/2/1980")));
g2 = new GrupaStudenti("2241", "AIA", 2);
g2.lista.add(new Persoana("Pop",
"Ioana",formatDate.parse("10/10/1980")));
g2.lista.add(new Persoana("Vasi",
"Alex",formatDate.parse("25/12/1979")));
} catch (ParseException e) {
e.printStackTrace();
}
}
void metodaButon(View v){
deAfisat.setText(g1.toString()+"\n\n"+g2.toString());
b1.setChecked(false);
b2.setChecked(false);
}
void metodaRadioButton(View view){
if(view.getId()==R.id.radioButton1)
deAfisat.setText(g1.toString());
if(view.getId()==R.id.radioButton2)
76
deAfisat.setText(g2.toString());
}

@Override
protected void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setGrupeStudenti();

deAfisat=(TextView)findViewById(R.id.textView);
b=(Button)findViewById(R.id.button);

b1=(RadioButton)findViewById(R.id.radioButton1);

b2=(RadioButton)findViewById(R.id.radioButton2);
}
}

77
78
Conectarea la Internet

Metodă care primește ca argument un șir de caractere și îl


formatează pentru a respecta șablonul unui URL. Poate
genera excepții.

//construieste un URL
public static URL buildUrl(String numeComponenta) {
URL urlFinal = null;
try {
urlFinal = new URL(UrlBaza+numeComponenta);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return urlFinal;
}

79
Metoda GetResponse primește ca argument un URL și
deschide o conexiune HTTP la Internet. În acest moment nu
comunică cu rețeaua încă. Metoda primește un flux de octeți
in, pe care îl folosește ca argument pentru a crea o instanța
Scanner care permite parsarea fluxurilor de octeți serializate
care conțin tipuri primitive și șiruri de caracte. Pentru aceasta
folosește expresii regulate (există mai multe metode prin care
se poate face această citire, detalii:
http://stackoverflow.com/questions/309424/read-convert-an-
inputstream-to-a-string) .
Când nu mai are octeți primiți pe in, închide fluxul. Poate
arunca excepții. Prin setarea \A la începutul fluxului se
forțează citirea întregului conținut al fluxului în următorul
token. De pe rețea pot veni pachete de diferite dimensiuni.
Codul permite alocarea/dealocarea bufferelor și codarea

80
fluxului (din UTF-8 folosit implicit pentru json și javaScript
în UTF-16 folosit de Android).

UTF-8 -> UTF-16

//primeste un raspuns HTTP pentru URL argument


public static String getResponse(URL urlFinal) throws
IOException {
HttpURLConnection connection =
(HttpURLConnection) urlFinal.openConnection();
try {
InputStream in = connection.getInputStream();

Scanner scanner = new Scanner(in);


scanner.useDelimiter("\\A");

81
boolean hasInput = scanner.hasNext();
if (hasInput) {
return scanner.next();
} else {
return null;
}
} finally {
connection.disconnect();
}
}

82
Permisiuni
Când se instalează un APK, aceasta primește un ID Linux
unic pentru fiecare utilizator și rulează în propria instanță în
mediul de rulare Android. Astfel, fiecare aplicație este
“închisă” (fișierele, procesele și alte resurse nu sunt accesibile
altor aplicații) pentru a nu afecta funcționarea altor aplicații
sau a nu compromite date sensibile (conexiunea la Internet,
baze de date, locația geografică). Permisiunea la resursele
sensibile se include de obicei în fișierul
.app.manifest.AndroidManifest.xml pentru a nu fi cerute
utilizatorului la fiecare rulare.
Lista cu permisiuni se găsește la adresa:
https://developer.android.com/guide/topics/permissions/index
.html
Începând cu Android 6.0 Marshmallow multe permisiuni sunt
implicite. La variatele mai vechi de Andoid erau cerute
83
utilizatorului. Se obișnuiește să se seteze numai acele
permisiuni absolut necesare (nu toate). Pentru anumite
permisiuni este bine să se ceară acordul utilizatorului
(exemplu, camera, locația geografică).

Exemplu de setare de acces la Internet în fișierul


AndroidManifest.xml

<uses-permission
android:name="android.permission.INTERNET" />

84
Fire de execuție
Mediul de rulare Android este multitasking și încurajează
folosirea firelor de execuție.
Pot fi create câte un fir de execuție pentru:
 fereastra grafică de interacțiune cu utilizatorul,
 pentru conexiunea la Internet,
 pentru lucrul cu baze de date,
 pentru muzică, etc.

O aplicație poate fi creată ca având mai multe fire de execuție


care lucrează concurent (SO Android poate rula mai multe
fire de execuție pe diferite core-uri ale procesorului, sau poate
aloca intervale de timp – time slice – pe același core).

85
Firul principal este fereastra UI care tratează evenimente de la
utilizator și senzori.

Accesul la Internet se definește într-un fir secundar.

Toate firele secundare trebuie să comunice cu firul principal


(UI) prin taskuri asincrone.

86
Task asincron
Permite rularea unui task într-un fir de execuție secundar.
Clasa AsyncTask este generică și trebuie imbricată în clasa cu
care vrea să comunice. Are un constructor cu parametri de
dimensiune variabilă (definite cu ... ca fiind vectori de
variabile).
Clasa AsyncTask are trei tipuri care corespund celor patru
funcții care se suprascriu în aplicație:
1. parametrul - tipul de parametru trimis taskului în timpul
execuției - doInBackground
2. progresul – folosit pentru update-ul taskului secundar –
onProgressUpdate
3. rezultat – tipul rezultatului taskului secundar –
onPostExecute, onPreExecute.

87
Exemplu – InternetConnection
În fișierul AndroidManifest.xml trebuie setate drepturile
pentru accesul la Internet.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="internetconnection.com.example.internetconnection">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".InternetConnection">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>
</application>

</manifest>

88
Fișierul InternetConnection.java care deschide fereastra
principală are descrise 2 variante de tratare a evenimentului
pe buton. Varianta 1 adaugă în fișier un ascultător. Varianta 2
definește o funcție care a fost adăugată în designul interfeței
grafice prin xml (android:onClick). Se definește clasa
imbricată RequestTask pentru a crea un task asincron care va
trata conexiunea la Internet.
public class InternetConnection extends AppCompatActivity {
private EditText url;
private Button butonAfiseaza;
private TextView viewCurs, viewUrl;
private DatePicker data;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_internet_connection);

89
url = (EditText) findViewById(R.id.editText);
butonAfiseaza = (Button) findViewById(R.id.button);
viewCurs = (TextView) findViewById(R.id.textView1);
viewUrl = (TextView) findViewById(R.id.textView2);
data=(DatePicker)findViewById(datePicker);
//intoarce data curenta
Calendar calendar = Calendar.getInstance();
data.setMaxDate(calendar.getTimeInMillis());

//varianta 1 de tratare a evenimentului click pe buton


butonAfiseaza.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) {
String urlRequestString =
data.getYear()+"/"+(data.getMonth()+1)+"/"+data.getDayOfMonth()+"/e
ur";
URL urlRequestUrl =
InternetTools.buildUrl(urlRequestString);
viewUrl.setText(urlRequestUrl.toString());
new RequestTask().execute(urlRequestUrl);
}
});
}

//varianta 2 de tratare a evenimentului click pe buton


//in fisierul activity_internet_connection.xml se seteaza

90
pentru buton proprietatea
//android:onClick="buttonInternetRequest"
/*public void buttonInternetRequest(View v){
String urlRequestString =
data.getYear()+"/"+data.getMonth()+"/"+data.getDayOfMonth()+"/eur";
URL urlRequestUrl =
InternetTools.buildUrl(urlRequestString);
viewCurs.setText(urlRequestUrl.toString());
viewUrl.setText(url.toString());
new RequestTask().execute(urlRequestUrl);
}*/

//clasa imbricata care trateaza un task asincron pentru cererea


de pe internet

public class RequestTask extends AsyncTask<URL, Void, String> {

@Override
protected String doInBackground(URL... params) {
URL searchUrl = params[0];
String urlResults = null;
try {
urlResults = InternetTools.getResponse(searchUrl);
} catch (IOException e) {
e.printStackTrace();
}

91
return urlResults;
}

// afiseaza rezultatele in TextView


@Override
protected void onPostExecute(String getResults) {
if (getResults != null && !getResults.equals("")) {
viewCurs.setText("1 EUR = "+getResults+" RON");
}
}
}
}

În metoda doInBackground se apelează metode care tratează


conexiunea la Internet și care sunt definite în clasa
InternetTools.java
public class InternetTools {

final static String UrlBaza =


"http://www.infovalutar.ro/bnr/";
//"http://www.infovalutar.ro/bce/"

92
//formatul este
"http://www.infovalutar.ro/bnr/an/luna/zi/moneda"

//construieste un URL
public static URL buildUrl(String numeComponenta) {
URL urlFinal = null;
try {
urlFinal = new URL(UrlBaza+numeComponenta);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return urlFinal;
}

//primeste un raspuns HTTP pentru URL argument


public static String getResponse(URL urlFinal) throws
IOException {
HttpURLConnection connection = (HttpURLConnection)
urlFinal.openConnection();
try {
InputStream in = connection.getInputStream();

Scanner scanner = new Scanner(in);

93
scanner.useDelimiter("\\A");

boolean hasInput = scanner.hasNext();


if (hasInput) {
return scanner.next();
} else {
return null;
}
} finally {
connection.disconnect();
}
}
}

94
95
Exemplu – RSSFeedExample
Aplicația deschide o conexiune Internet și preia un fișier web
de pe un site care oferă rss-uri. Parsează fișierul xml preluat,
respectând structura acestuia. Caută doar tag-urile item și din
acesteia preia doar tag-urile title și emsc:time.

Se preia un fișier xml de pe un flux web de pe un rss (Really


Simple Syndication) de la adresa (ultimele 50 cutremure la
nivel global)
http://www.emsc-csem.org/service/rss/rss.php?typ=emsc:

Structura fișierului xml cu rss este:

96
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:geo="http://www.w3.org/2003/01/geo/"
xmlns:emsc="http://www.emsc-csem.org" >
<channel>
<title>EMSC - Last 50 earthquakes worldwide</title>
<link>http://www.emsc-csem.org/</link>
<description>Real-time - Last 50 earthquakes worldwide</description>
<language>en</language>
<image>
<title>EMSC - CSEM</title>
<url>http://static2.emsc.eu/Images/emsc_200.png</url>
<link>http://www.emsc-csem.org</link>
</image>
<generator>EMSC - CSEM</generator>
<copyright>EMSC - CSEM</copyright>
<item>
<title>ML 2.2 CENTRAL ITALY</title>
<link>http://www.emsc-
csem.org/Earthquake/earthquake.php?id=578008</link>
<geo:lat>42.86</geo:lat>
<geo:long>13.23</geo:long>
<emsc:depth>12 </emsc:depth>
<emsc:magnitude>ML 2.2</emsc:magnitude>
<emsc:time>2017-03-20 09:20:22 UTC</emsc:time>
<pubDate>Mon, 20 Mar 2017 09:30:00 +0000</pubDate>
<status>REVIEWED</status>
<guid>http://www.emsc-
csem.org/Earthquake/earthquake.php?id=578008</guid>
<comments>2017-03-20 09:20:22 UTC</comments>
<description>

97
</description>
</item>
</channel>
</rss>

98
Pentru a parsa fișierul preluat de pe rss din format xml în
format List<RssFeedModel> se folosește metoda parseFeed.
Metoda caută toate tag-urile title și time care fac parte din tag-
ul item și preia valorile text găsite în acestea. Cu aceste valori
creează o instantă a clasei RssFeedModel.java și, apoi, le
adaugă la lista formată din instanțe ale clasei RssFeedModel.
Când nu mai are nimic de parsat sau s-a închis fluxul de
intrare, metoda parseFeed returnează lista cu instanțe ale
clasei RssFeedModel.
Clasa RssFeedModel are ca date membre doar tag-urile care
interesează în rss.

99
public class RssFeedModel {

public String title;


public String time;

public RssFeedModel(String title, String time) {


this.title = title;
this.time = time;
}
public String toString(){
return "--"+title+"\n----"+time+"\n";
}
}

100
Clasa InternetTools.java are metoda buildURL care creează
un URL pe baza unui șir de caractere primit ca argument și
metoda getResponse care returnează un flux de octeți. Fluxul
de octeți este transmis metodei parseFeed care transformă
fluxul de octeți într-o listă de obiecte.
public class InternetTools {

final static String UrlBaza = "http://";

//construieste un URL
public static URL buildUrl(String numeComponenta) {
URL urlFinal = null;
try {
urlFinal = new URL(UrlBaza+numeComponenta);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return urlFinal;
}

//primeste un raspuns HTTP pentru URL argument

101
public static InputStream getResponse(URL urlFinal) throws
IOException {
HttpURLConnection connection = (HttpURLConnection)
urlFinal.openConnection();
InputStream in=null;
try {
in = connection.getInputStream();
return in;
} finally {
connection.disconnect();
}
}
}

102
Clasa care corespunde ferestrei principale MainActivity are:
 metoda onCreate care inițializează componentele grafice în
java.
 Metoda afiseazaButton care creează un URL pe baza unui
șir de caractere, îl afișează în fereastra principală și apelează
un task asincron care să deschidă conexiunea la Internet și
să aducă fișierul xml.
 Metoda listToString transformă lista de instanțe
RssFeedModel într-un șir de caractere pentru a putea fi
afișat în etichetă.
 Metoda parseFeed care transformă un flux de octeți într-o
listă de obiecte.
 Clasa imbricată RequestTask rescrie metodele unui task
asincron:

103
 Metoda doInBackground deschide o conexiune la Internet,
face o cerere de răspuns și răspunsul îl memorează într-un
flux de octeți InputStream pe care îl transformă într-o listă
de instanțe pe care o prelucrează ca șir de caractere.
 Metoda onPostExecute va afișa șirul de caractere rezultat în
urma transformărilor într-o etichetă care are atașat un
ScrollView.

104
public class MainActivity extends AppCompatActivity {

private Button rssButton;


private TextView rssTitle;
private TextView rssUrl;

private List<RssFeedModel> feedList;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

rssButton = (Button) findViewById(R.id.button);


rssTitle = (TextView) findViewById(R.id.rssTitle);
rssUrl = (TextView) findViewById(R.id.rssUrl);
}

public void afiseazaButton(View v){


String urlRequestString = "www.emsc-
csem.org/service/rss/rss.php?typ=emsc";
URL urlRequestUrl = InternetTools.buildUrl(urlRequestString);
rssUrl.setText(urlRequestUrl.toString());
new RequestTask().execute(urlRequestUrl);
}

public String listToString(List<RssFeedModel> list){


StringBuffer sirDeAfisat=new StringBuffer();
for(RssFeedModel p:list) {

105
sirDeAfisat.append(" ");
sirDeAfisat.append(p);
sirDeAfisat.append("\n");
}
return sirDeAfisat.toString();
}

public List<RssFeedModel> parseFeed(InputStream inputStream) throws


XmlPullParserException, IOException {
String title = null;
String time = null;
boolean isItem = false;
List<RssFeedModel> items = new ArrayList<>();

try {
XmlPullParser xmlPullParser = Xml.newPullParser();

xmlPullParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
xmlPullParser.setInput(inputStream, null);

xmlPullParser.nextTag();
while (xmlPullParser.next() != XmlPullParser.END_DOCUMENT) {
int eventType = xmlPullParser.getEventType();

String name = xmlPullParser.getName();


if(name == null)
continue;

if(eventType == XmlPullParser.END_TAG) {

106
if(name.equalsIgnoreCase("item")) {
isItem = false;
}
continue;
}

if (eventType == XmlPullParser.START_TAG) {
if(name.equalsIgnoreCase("item")) {
isItem = true;
continue;
}
}

Log.d("Fisier parsat", "Parsing tag ==> " + name);


String result = "";
if (xmlPullParser.next() == XmlPullParser.TEXT) {
result = xmlPullParser.getText();
xmlPullParser.nextTag();
}

if (name.equalsIgnoreCase("title")) {
title = result;
Log.d("de adaugat---", "title ==> " + title);
} else if (name.equalsIgnoreCase("emsc:time")) {
time = result;
Log.d("de adaugat---", "time ==> " + time);
}

if (title != null && time != null) {


if(isItem) {

107
RssFeedModel item = new RssFeedModel(title, time);
items.add(item);
}
title = null;
time = null;
isItem = false;
}
}
Log.d("##items", " ==> " + items.toString());

return items;
} finally {
inputStream.close();
return items;
}
}

private class RequestTask extends AsyncTask<URL, Void, String> {

protected String doInBackground(URL... params) {


URL searchUrl = params[0];
String urlResults = null;
feedList=null;
try {
InputStream inputStream =
InternetTools.getResponse(searchUrl);
feedList = parseFeed(inputStream);
return listToString(feedList);
} catch (IOException e) {
e.printStackTrace();

108
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return listToString(feedList);
}

protected void onPostExecute(String getResults) {


if (getResults != null && !getResults.equals("")) {
rssTitle.setText("#" + getResults);
//rssTime.setText(" " + getResults);
}
}
}
}

109
Interfața grafică are un buton și două etichete.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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"
tools:context="devicesscreens.com.example.rssfeedexample.MainActivity">

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Afiseaza"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/rssUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Url"

110
android:textSize="18sp"
app:layout_constraintStart_toStartOf="@+id/button"
app:layout_constraintTop_toBottomOf="@+id/button" />

<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="?android:attr/colorButtonNormal"
app:layout_constraintLeft_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/rssUrl">

<TextView
android:id="@+id/rssTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Location: "
android:textSize="18sp" />
</ScrollView>
</android.support.constraint.ConstraintLayout>

111
112
Exemplu – OperatoriCuIntregi
Într-o fereastră se culeg două numere întregi prin intermediul
unei zone de text EditText (text îngroșat, numere cu semn,
margini sus și jos de 20dp) și a unui Spinner (elemente în
intervalul (-5,5) definite în fișierul .res.values.strings.xml,
text îngroșat, margini sus și jos de 20dp). Se efectuează
operația de adunare sau înmulțire în funcție de alegerea unuia
din cele două butoane radio care se găsesc incluse într-un
grup de butoane. Grupul de butoane are ca background un
dreptunghi solid cu margini pe nuanțe de verde definit în
fișierul res.drawable.border.xml. Rezultatul este afișat într-o
zonă de text needitabilă TextView cu background definit prin
fișierul .res.drawable.border_top_bottom.xml.
Managerul de poziționare pentru componentele grafice va fi
LinearLayout, care aranjează componentele pe o singură
coloană sau un singur rând (verical/orizontal).
113
114
Fișierul activity_operatori_cu_intregi.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res
/android"

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/activity_operatori_cu_intregi"
android:layout_width="match_parent"
android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_m
argin"

android:paddingLeft="@dimen/activity_horizontal_m
argin"

android:paddingRight="@dimen/activity_horizontal_
115
margin"

android:paddingTop="@dimen/activity_vertical_marg
in"
android:orientation="vertical"
android:showDividers="middle"
android:weightSum="1">

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="number|numberSigned"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:textStyle="bold"
android:id="@+id/editareNumar1" />

<Spinner
android:layout_width="100dp"
116
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:textStyle="bold"
android:id="@+id/editareNumar2" />

<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:layout_marginLeft="40dp"
android:background="@drawable/border">

<RadioButton
android:text="+"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioButton1"
android:textSize="40dp"
117
android:onClick="radioButtonMethod"
/>

<RadioButton
android:text="*"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/radioButton2"
android:textSize="40dp"
android:onClick="radioButtonMethod"
/>

</RadioGroup>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="40dp"
android:layout_marginTop="40dp"
118
android:textSize="30sp"

android:background="@drawable/border_top_bottom"
android:id="@+id/viewRezultat" />

</LinearLayout>

Fișierul OperatoriCuIntregi.java
public class OperatoriCuIntregi extends
AppCompatActivity {
TextView rezultat;
EditText numar1;
Spinner numar2;
RadioButton radioButtonPlus,
radioButtonInmultit;

@Override
protected void onCreate(Bundle

119
savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_operatori_cu_int
regi);
rezultat = (TextView)
findViewById(R.id.viewRezultat);
numar1 =
(EditText)findViewById(R.id.editareNumar1);
numar2 =
(Spinner)findViewById(R.id.editareNumar2);
radioButtonPlus =
(RadioButton)findViewById(R.id.radioButton1);
radioButtonInmultit =
(RadioButton)findViewById(R.id.radioButton2);
ArrayAdapter<CharSequence> adapterSpinner
= ArrayAdapter.createFromResource(this,
R.array.numere_intregi,
android.R.layout.simple_spinner_item);
120
adapterSpinner.setDropDownViewResource(android.R.
layout.simple_spinner_dropdown_item);
numar2.setAdapter(adapterSpinner);
}

public void radioButtonMethod(View view){


int rez=0;
String nr1,nr2,op;
boolean checked = ((RadioButton)
view).isChecked();
nr1 = numar1.getText().toString();
nr2=numar2.getSelectedItem().toString();
if(view.getId()==R.id.radioButton1) {
rez =
Integer.parseInt(nr1)+Integer.parseInt(nr2);
op= "+";
} else {
rez =
121
Integer.parseInt(nr1)*Integer.parseInt(nr2);
op= "*";
}
rezultat.setText("("+nr1+") "+op+"
("+nr2+") = "+rez);
}
}

Fișierele strings.xml, border.xml, border_top_bottom.xml de


vizualizat în AndroidStudio.

122
Baze de date

Informațiile pot fi salvate fizic în:


 Fișiere interne – privat pentru aplicație
 Fișiere în memorii externe (SdCard fizic sau, mai nou,
emulat sau amândouă) sau în locații shared - disponibil
pentru aplicație.

123
Cum se salvează datele într-o aplicație Android:
 SharedPreferences – clasă care asigură salvarea unor
perechi (atribut, valoare) de date primitive (boolean, integer,
float, long, string). Această clasă este folosită de
AndroidPreferenceActivity pentru a salva date de setare (de
exemplu, locația).
 SQLite – salvează datele organizate în tabele, cu legături
între ele. Rândurile reprezintă înregistrări/intrări. Coloanele
reprezintă caracteristici/atribute.
 Firebase – bază da date shared
 XML, JSON - local

124
Etapele de lucru cu BD:
 Stabilirea numărului de tabele
 Determinarea structurii tabelelor și a relațiilor dintre
acestea
 Crearea tabelelor
 Operații cu tabelele (CRUD – create, remove, update,
delete - înregistrări) folosind SQL queries.
https://www.w3schools.com/sql/ - tutorial SQL
https://sqlite.org/doclist.html - documentație SQL

125
Pentru a defini structura unei baze de date se creează o
clasă Contract, care va acea cel mult un constructor private
(pentru a nu se putea instanția clasa). In interiorul acestei
clase de tip Contract se definește câte o clasă imbricată
pentru fiecare tabelă din BD. Contract va defini sub formă
de constante statice coloanele fiecărei tabele și va
implementa interfața BaseColumns.
Interfața BaseColumns are definită implicit data membră
_ID pentru cheia primară a tabelei. Nu este obligatoriu să fie
folosită.
De asemenea, folosirea acestei interfețe este recomandată
pentru o mai bună încadrare în framework-ul Android, dar
nu obligatorie.

126
Crearea unei tabele se face declarând o clasă numită de
obicei DBHelper (unde DB este numele bazei de date ales
de programator) care extinde clasa SQLiteOpenHelper.
Această clasă este folosită pentru a crea prima oară o tabelă
sau pentru a face update la o tabelă creată anterior. Metodele
onCreate și onUpgrade din clasa SQLiteOpenHelper vor fi
rescrise în clasa DBHelper.

127
Tipuri de date ale coloanelor în SQLite
Folosește un sistem de tipuri dinamice, la care tipul de date
este asociat cu datele pe care le conține, nu cu tipul
coloanei.
 NULL – valoare nulă.
 INTEGER – întreg cu semn, memorat pe 1, 2, 3, 4, 6, 8
bytes depinzând de mărimea valorii.
 REAL – memorare număr real pe 8 byte folosind
formatul IEEE pentru numere reale.
 TEXT – șir de caractere folosind codificare (UTF-8,
UTF-16BE sau UTF-16LE).
 BLOB – valoare memorată așa cum a fot introdusă.
 Boolean – ca valori întregi 0/1.

128
 Date –
o șiruri de caractere în formatul ("YYYY-MM-DD
HH:MM:SS.SSS") sau orice alt format definit explicit
o număr real care reprezintă numărul de zile de la data
24/11/4714 b.c.
o număr întreg care reprezintă numărul de secunde de la
data 01/01/1970.

129
Suport pentru pachete de biblioteci de clase
Există pachete de biblioteci (Support Library) care pot fi
incluse într-o aplicație mobilă. Fiecare din aceste biblioteci
sunt create pentru o anumită versiune de platformă și includ
diferite funcționalități.
Pentru a putea fi folosite, bibliotecile trebuie downloadate și
apoi incluse în aplicație.
De exemplu, în aplicația BazaDate în fișierul build.gradle al
aplicației se include la dependencies:
compile 'com.android.support:recyclerview-v7:26.1.0'

130
Exemplu - BazaDate
 res/values/colors.xml – definirea de culori
 res/drawable/rectangle.xml – definirea de detalii folosite
la afișarea componentelor grafice
 res/layout/persoana_list_item.xml – definește cum va fi
afișat un rând (compus din 3 etichete) din RecyclerView.
 res/layout/activity_main.xml definește organizarea
componetelor grafice într-un linearLayout vertical care
cuprinde
o un linearLayout orizontal cu o zonă de editare de text
pentru nume și prenume, ambele scrise cu litere mari
și o zonă de editare text pentru data în formatul
dd/mm/year.
o Un buton pentru adăugarea unei persoane
o RecyclerView pentru afișarea persoanelor din DB.

131
 app/build.gradle – trebuie adăugată linia
compile 'com.android.support:recyclerview-v7:26.1.0'

 java/pachet/PersoaneContract.java – conține clasa finală


PersoanaEntry care extinde interfața BaseColumns și
care descrie numele tabelului și numele coloanei
 java/pachet/PersoaneHelper.java – extinde clasa
SQLiteOpenHelper și redefinește metodele onCreate
(crează o tabelă definită de clasa PersoaneContract) și
onUpgrade (șterge și recreează o tabelă).

final String SQL_CREATE_PERSOANE_TABLE = "CREATE


TABLE " + PersoaneContract.PersoanaEntry.TABLE_NAME
+ " (" +
PersoaneContract.PersoanaEntry._ID + "
INTEGER PRIMARY KEY AUTOINCREMENT," +

132
PersoaneContract.PersoanaEntry.COLUMN_NUME_PERSOANA
+ " TEXT NOT NULL, "
Definirea de forma NOT NULL forțează ca toate
înregistrările să aibă definite valorile pentru coloana
respectivă. Astfel se previne inserarea de câmpuri
invalide.
 Java/pachet/PersoanaListAdapter.java – extinde clasa
RecyclerView.Adapter pentru a asigura legătura între
setul de date și RecyclerView care urmează să le afișeze.
RecyclerView este un container mai avansat decât
ListView pentru a afișa o listă de date și care permite
scroll (top-down) și swap (left-right). Trebuie definit un
layout (xml de tip Linear, Grid sau StaggeredGrid) și un
adapter (java). Clasa PersoanaListAdapter redefinește
mai multe metode și conține o clasă imbricată.

133
 Java/pachet/MainAdapter.java – are metode pentru a crea
tabela, pentru a adăuga/șterge o Persoana la tabelă,
pentru a obține toate persoanele din tabelă, pentru a trata
evenimentul de swap pe un rând din RecyclerView
(ItemTouchHelper).
 baza de date poate fi vizualizată în meniul Tools-
Android-Android Device Monitor—FileExplorer. In
directorul data/data/app-package se găsesc salvate
fișierele interne. Versiuni superioare API 23 au probleme
în a vizualiza acest director. Conținutul lui poate fi
vizualizat în emulator sau în FileExplorer instalat de
dispozitivul mobil.

134
Exemplu – BDFirebase

BD Firebase sunt sunt memorate sub forma unor structuri


JSON și permit salvarea următoarelor tipuri de date:
 String
 Long
 Double
 Boolean
 Map<String, Object>
 List<Object>

135
Structura JSON
JavaScript Object Notation

 Sunt fișiere text, pentru a memora și accesa date.


 Folosește notația obiectelor JavaScript.
 Datele sunt scrise sub formă de perechi {nume: valoare},
incluse între {}.
 Valorile pot fi: șir de caractere, număr, obiect JSON,
vector (cuprinse între [ ] ), boolean, null.
 JSON seamănă cu XML, dar în plus folosește ca date
vectori și nu are nevoie de un parser dedicat.

136
1. Se creeaza un proiect nou în consola Firebase:
https://console.firebase.google.com.
2. Se adaugă o nouă aplicație la proiectul Firebase.
Proiectul aplicației este realizat în Android Studio. La
Package name se trece applicationId din fișierul
app/build.gradle.

137
3. Se adaugă BD în Firebase la tipul de aplicatie: Android,
IOS sau Web.

138
4. Se face download la google-services.json în directorul
rădăcină /app al proiectului Android.

139
5. Se creează dependențele prin adăugarea Firebase la
SDK, se găsesc la adresa:
https://firebase.google.com/docs/android/setup?authuser=2

140
o În fișierul build.gradle de la nivelul proiectului
(<project>/build.gradle) se adaugă:
buildscript {
dependencies {
classpath 'com.google.gms:google-services:3.2.0'
}
}

o În fișierul build.gradle de la nivelul aplicației


(<project>/<app-module>/build.gradle) se adaugă:
dependencies {
compile 'com.google.firebase:firebase-database:11.8.0'
}
//la sfarsitul fisierului
apply plugin: 'com.google.gms.google-services'

141
6. Se setează regulile de securitate

In tabul Rules sunt trecute regulile implicite de acces la


BD:
{
"rules": {
".read": "auth != null",
142
".write": "auth != null"
// data written to root must be a string less than 100
characters
".validate": "newData.isString() && newData.val().length
< 100"

}
}
Le setăm true (ceea ce asigură un acces public, oricine
poate citi sau scrie în BD), doar în etapa de dezvoltare, și
apoi le Publish.

143
Regulile se pot seta pentru nodul rădăcină cu efect asupra
nodurilor copii sau pot fi setate pentru un nod copil, caz în
care sunt suprascrise de regulile nodului părinte. Valorile
pentru reguli pot fi true, false sau pot fi date utilizatorilor
drepturi de accest "$uid === auth.uid" sau alte reguli mai
specificate prin cod de tip JavaScript sau prin queries.
".indexOn": ["nume","prenume"],

144
7. Pentru rulare este nevoie de un dispozitiv (fizic sau
emulat) care să aibă instalată o versiune recentă de
Google Play Services. Când se folosește un dispozitiv
virtual, trebuie verificat în AVD Manager, în coloana
Target să fie trecut (Google APIs).
8. Scrierea unei înregistrări într-o tabelă se face:

o În cod java în Android Studio


bdReference.push().setValue(instanta_de_scris)

//actiune pe butonul Adauga


public void addToPersoana(View view) {
if (numePrenumeEditText.getText().length() == 0 ||
dataNastereEditText.getText().length() == 0) {
return;
} else {
try {
//preia datele introduse de la utilizator in UI si
creeaza o noua Persoana
String nume =

145
numePrenumeEditText.getText().toString().split(" ")[0];
String prenume =
numePrenumeEditText.getText().toString().split(" ")[1];
SimpleDateFormat dataFormat = new
SimpleDateFormat("dd/MM/yyyy");
Date dataNastere =
dataFormat.parse(dataNastereEditText.getText().toString());
numePrenumeEditText.setText("");
dataNastereEditText.setText("");
Persoana pers= new Persoana(nume,prenume, dataNastere);
// adauga un item Persoana la DB
persoaneReference.push().setValue(pers);

} catch (ParseException ex) {


// handle parsing exception if date string was different
from the pattern applying into the SimpleDateFormat contructor
}
}
}

146
o În browser

147
9. Citirea din tabele se face printr-un ascultător, deoarece
BD Firebase sunt realtime și astfel vor notifica aplicația
când are loc o modificare în BD.
o Pentru citire se folosește o instantă a
ChildEventListener pentru care trebuiesc rescrise 5
metode care vor fi activate doar dacă un nod copil al
tabelei (echivalent cu o înregistare în tabelă) va fi
modificat:
 onChildAdded – este apelată ori de căte ori se
adaugă o nou înregistrare în tabelă;
 onChildChanged – este apelată când se modifică o
înregistrare;
 onChildRemoved – când se șterge o înregistrare;
 onChildMoved – când se schimbă poziția unei
înregistrări;

148
 onCancelled – când apare o eroare la încercarea de
modificare a înregistrărilor.
o Pentru citire se poate adăuga un ValueEventListener la
referința la BD, caz în care trebuie rescrise metodele
 onDataChange
 onCancelled
persoaneReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
listaPersoane.clear();
Iterator<DataSnapshot> dataSnapshots =
dataSnapshot.getChildren().iterator();
while (dataSnapshots.hasNext()) {
DataSnapshot dataSnapshotChild = dataSnapshots.next();
Persoana persoana =
dataSnapshotChild.getValue(Persoana.class);
listaPersoane.add(persoana);
}
mAdapter.notifyDataSetChanged();
}

149
@Override
public void onCancelled(DatabaseError databaseError) {

}
});

150
10. Ștergerea înregistrărilor din tabelă se face prin:
BDReference.removeValue();
Sau prin poziționarea pe nodul de șters cu metoda
BDReference.setValue(null);

În exemplu BDFirebase ștergerea:


public void onSwiped(RecyclerView.ViewHolder viewHolder,
int swipeDir) {
// preia id-ul item-ului pe care s-a facut swipe
final int id = viewHolder.getAdapterPosition();
listaPersoane.remove(id);
//sterge tot continutul tabelei si adauga doar
itemii ramasi in listaPersoane
persoaneReference.removeValue();
for(Persoana p:listaPersoane)
persoaneReference.push().setValue(p);
}
}).attachToRecyclerView(persoaneRecyclerView);

151
Exemplu – FileIO
Aplicația citește dintr-o zonă de editare de text un text (pe
mai multe rânduri) și îl salvează într-un fișier local
(data/data/app.package) la apelul unui buton. La apelul altui
buton citește fișierul salvat anterior (chiar dacă aplicația a fost
închisă, citește ceea ce a fost salvat la ultima rulare) și îl
afișează într-o etichetă.
Fișierul este accesibil doar în directorul aplicației și va fi șters
când este dezinstalată aplicația.
Vizualizarea fișierului se poate face pentru maxim API 23 în
meniul Tools- Android-Android Device Monitor—
FileExplorer. In directorul data/data/app-package se găsesc
salvate fișierele interne. Conținutul lui poate fi vizualizat și
în emulator sau în FileExplorer instalat de dispozitivul
mobil.

152
AndroidManifest.xml trebuie să seteze drepturile de acces la
fișiere salvate extern.
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORA
GE" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAG
E"/>

153
154
Componente aplicații mobile
Sunt patru tipuri de componente:
1. Activities – permite dezvoltarea interacțiunii aplicație-
utilizator (cum începe aplicația, cum se navighează în
aplicație cu Back button sau între aplicații cu Recent
button). Majoritatea interacționează direct cu utilizatorul
și sunt ferestre (full-screen, floating-window,
ActivityGroup – inclus în altă activitate).
2. Services – sunt puncte de intrare în aplicație care permit
rularea de taskuri în fundal (de exemplu, procese la
distanță, conexiune la internet, redă muzică în fundal). Nu
au GUI.
3. Broadcast receivers – sunt puncte de intrare în aplicație
care realizează evenimente în afara fluxului de evenimente
stabilite de utilizator. Aplicația poate primi anunțuri chiar
dacă nu rulează (de exemplu, alarma unei notificări, nivel
155
scăzut baterie, fotografierea, download finalizat).
Broadcast receiver nu afișează o componentă grafică, pot
crea o notificare în status bar.
4. Content providers – sunt puncte de intrare în aplicație care
asigură accesul la date ale aplicației, identificate prin URI,
memorate local sau Web printr-o BD SQLite (de exemplu,
informații utilizator). Mai multe aplicații pot avea acces la
același Content provider.

Pentru toate aceste componente (pentru a fi vizibile în


aplicație și pentru a rula) trebuiesc specificate tag-uri în
AndroidManifest.xml.
<activity>
<service>
<receiver>
<provider>
156
Activarea componentelor se realizează prin clasa Intent.
Apelul constructorului Intent se poate face explicit
specificând componenta ce urmează a fi activată sau implicit
descriind ce fel de acțiune se va realiza și lăsând sistemul să
caute o componentă care poate realiza acțiunea.

157
158
Activity lifecycle
Exemplu FereastraSecundara
Aplicație care va deschide o fereastră secundară din
fereastra principală.
Metoda asociată butonului din fereastra principal care are ca
scop deschiderea ferestrei secundare este
deschideFereastra2(View v).
Pentru a crea o activitate secundară se alege în meniu File-
New-Activity-EmptyActivity și se fac toate setările de
layout în fișierul xml și cele de tratare de evenimente în
fișierul java asociat.
Adăugarea unui icon la ActionBar (bara de titlu) se face
prin metoda setLogo().

public class MainActivity extends AppCompatActivity {


EditText editText1;
Button button1;
public static final String EXTRA_MESSAGE =
159
"ferestre.com.example.fereastrasecundara.MESSAGE";

protected void onCreate(Bundle


savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText1 = (EditText)
findViewById(R.id.editText1);
button1 = (Button) findViewById(R.id.button1);
actionBar=getSupportActionBar();
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setLogo(R.mipmap.title_icon);
actionBar.setDisplayUseLogoEnabled(true);
}

public void deschideFereastra2(View v){


Intent intent = new Intent(this,
Main2Activity.class);
String valoareDeTransmis =
editText1.getText().toString();
intent.putExtra(EXTRA_MESSAGE,
160
valoareDeTransmis);
startActivity(intent);

}
}
Clasa Intent asigură legătura dintre două component ale
unei aplicații (de exemplu două activități) și reprezintă
intenția aplicației de a face ceva. Parametrii constructorului
clasei Intent sunt componenta curentă (Context) și
componenta viitoare în care aplicația va furniza Intent-ul.
Metoda putExtra transmite perechi cheie-valoare
(EXTRA_MESSAGE mesaj definit ca dată membră finală a
clasei și message). Cheia are ca prefix numele pachetului
pentru a asigura unicitatea în cazul în care se
interacționează cu alte aplicații.
Metoda startActivity() pornește o instanță specificată ca
Intent.
161
Fișierul app/manifests/AndroidManifest.xml va conține
specificate cele două activități și legătura dintre ele.

<?xml version="1.0" encoding="utf-8"?>


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

package="ferestre.com.example.fereastrasecundara">

<application
android:allowBackup="true"
android:icon="@mipmap/titleIcon"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action
162
ndroid:name="android.intent.action.MAIN" />

<category android:name =
"android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main2Activity"
android:label="@string/fereastra2"
android:parentActivityName=".MainActivity" >
<meta-data android:name =
"android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
</application>

</manifest>

163
Exemplu - Internaționalizare
Android asigură suport pentru diferite limbi și culturi (format
de dată, timp, numere, monedă) prin intermediul setărilor
legate de localizare.
Diferitele variante pentru diferite limbi sunt memorate în
directoare separate în directorul /resources, respectând
modelul:
<resource type>-b+<language code>[+<country code>]

Fișierul string.xml are câte o variantă în fiecare director


corespunzător unei limbi. Se păstrează denumirile variabilelor
folosite în setarea caracteristicilor componentelor grafice.

Apelul componentelor grafice în fișierele Java se face ca și


cum ar fi o singură variantă de limbă.

164
O listă cu setările pentru limbă:
http://stackoverflow.com/questions/7973023/what-is-the-list-
of-supported-languages-locales-on-android

Pentru a schimba setările de limbă, trebuie schimbate setările


din aplicația Settings a dispozitivului mobil.

165
166
167
Unitățile de măsură
pentru imagini folosite în Android sunt:
 dp – unitate de măsură abstractă care se bazează pe
densitatea ecranului (Density-independent Pixel). Pentru
un ecran de 160 dpi (dots per inch) 1dp=1px
 in – (inch) = 25.4 mm dimensiune fizică
 mm – (milimetri) dimensiune fizică
 pt – (points) = 1/72 inch
 px – (pixels) este dependentă de dimensiunea fizică a
ecranului
 sp – unitate de măsură abstractă scalară folosită pentru
fonturi (Scale-independent Pixel), care permite adaptarea
la densitatea ecranului și preferințele utilizatorului.

168
Dispozitive cu ecrane diferite
Un proiect poate fi creat pentru a arăta diferit pe diferite
dispozitive mobile, cu diferite dimensiuni. Astfel, se poate
adapta organizarea și dimensiunea componentelor grafice la
dimensiunile spațiului de afișare.
Ecranele dispozitivelor mobile se caracterizează prin:
 dimensiune (screen_size: small, normal, large, xlarge).
Pentru fiecare dimensiune trebuie creat un fișier
layout.xml (cu același nume) în directorul:
res/layout-<screen_size>
 densitate (density : low (ldpi), medium (mdpi), high
(hdpi), extra high (xhdpi)).

169
Dimensiunea absolută a ecranului nu este importantă.
Importantă este organizarea componentelor grafice în layout.
https://developer.android.com/guide/topics/resources/providin
g-resources.html#BestMatch
Pentru ecran, implicit se consideră orientarea Portrait.
Pentru orientarea Landscape se creează directorul layout-land
MyProject/ res/
layout/ # default (portrait)
main.xml
layout-land/ # landscape
main.xml
layout-large/ # large (portrait)
main.xml
layout-large-land/ # large landscape
main.xml

170
https://developer.android.com/training/multiscreen/index.html
Adăugarea unor imagini diferite pentru diferite setări de
limbă se face introducând fișiere imagine cu același nume în
directoarele fiecărei limbi:

MyProject/ res/
mipmap/ # default (Engleza)
fisier_imagine.jpg/png/bmp
mipmap-b+fr+FR/ # franceza
fisier_imagine.jpg/png/bmp

Fișierele imagine trebuie să aibă aceleași caractersitici


(dimensiune, codare, etc.).

171
Pentru a pregăti aplicația pentru diferite tipuri de ecrane,
trebuiesc incluse în proiect resurse adaptate diferitelor
caracteristici.
În directorul res avem următoarele subdirectoare care pot fi
setate pentru caracteristicile ecranelor:
 res/drawable/ - fișiere imagine (.png, .9.png, .jpg, .gif)
sau Xml care pot fi compilate în fișiere imagine.
Necesită foldere denumite cu <density-qualifiers>
pentru diferite caracteristici ecran (hdpi, mdpi, ldpi,
xhdpi, etc.)
 res/mipmap – fișiere imagine, cum ar fi iconițele pentru
Action Bar. Necesită foldere denumite cu <density-
qualifiers> pentru diferite caracteristici ecran (hdpi,
mdpi, ldpi, xhdpi, etc.)

172
 res/layout/ - fișiere Xml pentru organizarea
componentelor grafice
 res/anim/ - fișiere animație, necesită foldere denumite
cu <qualifiers> pentru diferite caracteristici ecran
 res/xml/ - fișiere xml, necesită foldere denumite cu
<qualifiers> pentru diferite caracteristici ecran
res/raw/ (required if you have any res/raw-
<qualifiers> folders)
Imaginile incluse într-un proiect Android pot fi:
 create cu alte aplicații
 generate folosind aplicația Image Asset Studio pusă la
dispoziție de Android Studio
https://developer.android.com/studio/write/image-asset-
studio.html
173
Imaginile, pentru a putea fi scalate, trebuiesc generate în
format vectorial astfel:
 xhdpi: 2.0
 hdpi: 1.5
 mdpi: 1.0 (baseline)
 ldpi: 0.75
Exemplu: pentru o imagine de 100x100 pentru dispozitive cu
densitate mdpi, trebuiesc generate următoarele resurse:
200x200 – xhdpi, 150x150 – hdpi, 75x75 – ldpi.

174
Pentru a crea o iconiță a aplicației în modul de vizualizare
Android, se selectează
res->New->Image Asset sau res->New->Vector Asset

175
Se pot genera astfel iconițe pentru aplicație (launcher icons)
ce vor fi salvate în directorul res/mipmap, iconițe pentru
ActionBar sau pentru Tab-uri ce vor fi salvate în directorul
res/drawable, diverse alte imagini ce vor fi salvate în
directorul res/drawable. Iconițele pot fi create pe baza unor
șabloane ClipArt sau a unor imagini alese de utilizator în
format (svg sau psd).
Pentru crearea imaginilor vectoriale se pot folosi aplicații
dedicate (ex. Online https://vectr.com).
De exemplu, atunci când se creează o iconița pentru aplicație,
în resurse vor fi introduse următoarele fișiere:
res/
mipmap-mdpi/ic_launcher.png (48x48 pixels)
mipmap-hdpi/ic_launcher.png (72x72)
mipmap-xhdpi/ic_launcher.png (96x96)
mipmap-xxhdpi/ic_launcher.png (144x144)
mipmap-xxxhdpi/ic_launcher.png (192x192)
176
Exemplu - DevicesScreens

177
178
179
Includerea unei iconițe în ActionBar s-a făcut în fișierul
principal Java:
ActionBar actionBar;

actionBar=getSupportActionBar();
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setLogo(R.mipmap.ic_action_bar);
actionBar.setDisplayUseLogoEnabled(true);

180

S-ar putea să vă placă și