Documente Academic
Documente Profesional
Documente Cultură
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.
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,
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
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
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
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.
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)
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.
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>
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);
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";
}
}
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
@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ă.
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();
}
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();
}
}
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>
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
//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).
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ă).
<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.
85
Firul principal este fereastra UI care tratează evenimente de la
utilizator și senzori.
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">
<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" />
</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());
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);
}*/
@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;
}
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;
}
93
scanner.useDelimiter("\\A");
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.
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 {
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 {
//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;
}
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 {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
105
sirDeAfisat.append(" ");
sirDeAfisat.append(p);
sirDeAfisat.append("\n");
}
return sirDeAfisat.toString();
}
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();
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;
}
}
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);
}
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;
}
}
108
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return listToString(feedList);
}
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);
}
122
Baze de date
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'
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
135
Structura JSON
JavaScript Object Notation
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'
}
}
141
6. Se setează regulile de securitate
}
}
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:
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);
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);
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.
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().
}
}
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.
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>]
164
O listă cu setările pentru limbă:
http://stackoverflow.com/questions/7973023/what-is-the-list-
of-supported-languages-locales-on-android
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
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