Intel, …, il cui obiettivo è sviluppare standard aperti per dispositivi mobili. E’ un gruppo di
aziende che lavorano con le tecnologie mobili. Membri:
Operatori mobili (Mobile Operator): Vodafone, T-Mobile, Telecom, etc.
Produttori di semiconduttori (Semiconductor Companies): Intel, NVIDIA, ARM, etc.
Produttori di dispositivi (Handset Manufacturers): ACER, ASUS, HTC, Lenovo, etc.
Produttori di software (Software Companies): OMRON, Google, eBay, etc.
Compagnie per la commercializzazione (Commercialization Companies): Aplix, Noser
Engineering, etc.
BYTECODE
Sviluppo in Java, trasformazione in bytecode Dalvik fino alla versione 4.4
Dalvik è una macchina virtuale, ottimizzato per sfruttare la poca memoria presente
nei dispositivi mobili.
Essa è spesso associato alla Macchina Virtuale Java, anche se il bytecode con cui
lavora non è Java.
E’ basato su tecnologia JIT (just-in-time): l’app è compilata in parte dallo
sviluppatore, poi Dalvik (interprete) esegue il codice compilandolo in linguaggio
macchina in tempo reale per ogni esecuzione dell’app stessa.
Funzionamento:
1. Si scarica un file .apk dal Playstore.
2. Una volta installato si crea un file .dex contenente il bytecode.
3. Durante l’esecuzione di un programma la Dalvik si occupa di tradurre il
bytecode in linguaggio macchina così da divenire eseguibile.
4. Una volta terminata l’operazione il codice tradotto viene per e alla prossima
esecuzione del programma si ricomincia dal punto 1.
ART (android 5.0+) è il nuovo ambiente di Runtime che ha migliorato vari aspetti
critici (per esempio la gestione della memoria).
E’ basato su tecnologia AOT(ahead-of-time): esegue l’intera compilazione del codice
durante l’installazione dell’app e non durate l’esecuzione stessa del software.
Ne consegue un vantaggio in termini di prestazioni e gestione delle risorse, ma un
maggior tempo per l’installazione di un app.
Funzionamento:
1. Come Dalvik.
2. Al momento dell’installazione l’applicazione viene anche compilata creando un
file .ELF eseguibile.
3. Una volta avviata l’app il codice sarà già pronto per essere eseguito e al
termine dell’esecuzione rimarrà tale.
ACTIVITY MANAGER
Activity: è un qualcosa che possiamo associare a una schermata, che permette non
solo la visualizzazione o la raccolta di informazioni ma, in modo più generico, è lo
strumento fondamentale il quale l’utente interagisce con l’applicazione.
E’ fondamentale capirne il ciclo di vita, gestito dall’Activity Manager: responsabilità
di questo componente sarà l’organizzazione delle varie schermate di un’applicazione
in uno stack (pila LIFO) per la navigazione, a seconda dell’ordine di visualizzazione
delle stesse sullo schermo dei diversi dispositivi.
Quando si avvia un’app, per esempio musica, ad ogni azione compaiono nuove
attività.
PACKAGE MANAGER
Database che tiene traccia delle app installate nel dispositivo.
Consente ad un’app di trovare, mettersi in comunicazione, richiedere servizi ad
un’altra app.
Classe per il recupero di vari tipi di informazioni relative ai pacchetti applicativi che
sono attualmente installati sul dispositivo.
E’ possibile trovare questa classe attraverso il metodo getPackageManager().
WINDOW MANAGER
Gestisce le finestre che compongono un’app, esempio:
- notification bar;
- main application;
- subwindow.
L’interfaccia che le applicazioni utilizzano per comunicare con il window manager.
Utilizzare Context.getSystemService(Context.WINDOW_SERVICE) per ottenere una di
queste.
Ogni istanza window manager è associata a un particolare display.
Per ottenere un WindowManager per un differente display, usare
createDisplayContext(Display), per ottenere un Context per quel display utilizzare
Context.getSystemService(Context.WINDOW_SERVICE) per avere il WindowManager.
Il modo più semplice per mostrare una finestra su un altro display è di creare una
Presentation (presentazione). Essa permetterà di ottenere automaticamente un
WindowManager e un Context per il display.
VIEW SYSTEM
Elementi della UI (icone, testo, pulsanti, …).
Nell’app del telefono vi sono diversi componenti del View System, p.e i pulsanti e
textViews.
Questa classe rappresenta gli elementi base per i componenti dell’interfaccia utente.
Una View occupa un’area rettangolare sullo schermo ed è responsabile del disegno e
della gestione degli eventi.
Una View è la classe base per i widgets, che vengono usati per creare componenti UI
interattivi (pulsati, campi di testo, ecc).
La sottoclasse ViewGroup è la classe base per i layout, che sono contenitori invisibili
che contengono altre Views (o altre ViewGroup) e definiscono le proprietà dei loro
layout.
CONTENT PROVIDER
Database che consente alle app di memorizzare e condividere le informazioni
(persistenti).
Ad esempio, l’app del telefono accede alle informazioni dei contatti e li usa per
effettuare le telefonate; allo stesso modo l’app di messaggistica utilizza le
informazioni presenti nei contatti per inviare sms, come le app dei social media.
Questo deve avvenire in modo controllato e sicuro, attraverso interfacce (per
l’esecuzione delle operazioni di CRUD Create Retrieve Update Delete) predefinite che
caratterizzano il ContentProvider.
I ContentProviders gestiscono l’accesso a un insieme strutturato di dati.
Incapsulano i dati e forniscono meccanismi per la definizione di dati sicuri.
Sono l’interfaccia standard che collega dati di un processo con codice in esecuzione
in un altro processo.
LOCATION MANAGER
Le applicazioni che gestiscono, tra le informazioni disponibili, quelle relative alla
localizzazione si chiamano Location Based Apllication (LBA) e possono essere
realizzate utilizzando API messe a disposizione del Location Manager.
Esso permette alle app di ricevere informazioni sul movimento e ralative alla
posizione (GPS) del dispositivo.
Consente di svolgere task precisi e specifici come trovare la posizione e direzione.
Questa classe fornisce l’accesso ai servizi di localizzazione del sistema.
Questi servizi consentono alle applicazioni di ricevere aggiornamenti periodici della
posizione geografica del dispositivo e il fuoco dell’Intent della specifica applicazione
quando il dispositivo entra in prossimità di una determinata area geografica.
Non si può istanziare questa classe direttamente; invece la si può recuperare
attraverso Context.getSystemService(Context.LOCATION_SERVICE).
Se non espresso diversamente, tutti i metodi LOCATION API richiedono i permessi
ACCES_COARSE_LOCATION o ACCESS_FINE_LOCATION.
NOTIFICATION BAR
Consente alle app di inserire informazioni nella Notification Bar, per esempio per
avvisare che si è verificato un dato evento.
Questo è il modo per avvisare l’utente che qualcosa è successo in background.
Le notifiche possono assumere varie forme diverse: segnale attraverso una
vibrazione, un LED, un’icona.
Ognuno dei metodi di notifica accetta un parametro int id e opzionalmente un tag
String, che può essere null.
Questi parametri vengono utilizzati per formare una coppia (tag, id) o (null, id); questa
coppia identifica la notifica della tua app per il sistema, in modo tale che la coppia sia
unica all’interno dell’app.
GRADLE
Gradle è uno strumento di build, Open Source che automatizza lo sviluppo di
applicazioni; inoltre esso usa un grafo aciclico diretto per determinare l’ordine di
esecuzione dei processi.
La caratteristica principale è quella di mettere a disposizione un Domain Specific
Language (DSL), ovvero un linguaggio specifico per un determinato dominio, che in
questa caso è la gestione della fase di build di applicazioni con Android.
Chiunque può estendere e personalizzare il proprio processo di build estendendo
task offerti dai plugin standard.
Ogni script Gradle è infatti equivalente al codice di un programma, ed esso esegue tre
diverse fasi:
- Inizializzazione: Gradle leggerà tutti i file di configurazione, creando per ciascuno
di questi un oggetto di tipo Project.
- Configurazione: l’oggetto Project viene alimentato dalle informazioni relative ai
vari task (compilazione, esecuzione di test, creazione di file apk e così via) da
eseguire; i task non sono indipendenti l’uno dall’altro, ma sono legati da vincoli di
sequenzialità; non possiamo testare se prima non abbiamo compilato.
- Esecuzione: Tutti i task vengono effettivamente eseguiti.
Tutti i file di Gradle sono contenuti in una cartella che si chiama Gradle Scripts, dove
vi è la presenza dei seguenti tre file:
- settings.gradle: viene usato da Gradle nella fase di inzializzazione per capire quali
siano i progetti e i moduli da gestire e di cui leggere le configurazione;
- build.gradle (Project: ApoBus): contiene alcune configurazioni che riguardano tutti
i moduli del nostro progetto; ed è composta da:
o buildscript: contiene la definizione delle dipendenze, ovvero delle eventuali
librerie di cui lo stesso Gradle necessita per il build della applicazione.
o repositories: definiamo le sorgenti delle nostre librerie, ovvero i repository
da cui ottenerle.
- build.gradle (Module: app): è associato al modulo principale che si chiama app.
SEMANTIC VERSIONING
Le librerie hanno un nome strutturato come segue:
<package-or-company>:<name>:<version>
Dopo i due punti (:) la seconda parte identifica il nome della libreria.
Le prime due parti sono obbligatorie, mentre la versione è opzionale ma iportante.
Il versioning presenta diverse cifre, nel caso della versione di build di Gradle sono tre
e rappresentano:
major.minor.patch
Il simbolo + indica tutte le release successive rispetto ad un livello di versioning,
quindi +, 1., 1.1.+
GRADLE WRAPPER
Consente di avere sempre di avere la versione più aggiornata di Gradle
gradle –wrapper.properties
ACTIVITY
Ciascuna schermata definisce due aspetti: l’insieme degli elementi grafici e la
modalità di interazione con essi.
Queste regole potranno essere definite attraverso righe di codice (modo imperativo)
oppure attraversi opportuni documenti XML di layout (modo dichiarativo) sfruttando
l’IDE di Android Studio.
Una activity gestisce gli elementi della GUI (equivale al controller dell’MVC).
Importante capirne il ciclo di vita e i metodi di callback.
Riceve le azioni degli utenti per consentirne l’interazione.
Esso specifica un compito elementare che un utente può compiere (esempio
effettuare una chiamata, aggiungere un contatto in agenda).
Una normale applicazione è composta da più schermate, esse si alternano molte
volte scambiandosi delle informazioni.
Per questo motivo Android organizza le attività secondo una struttura a stack dove
l’attività in cima è sempre quella attiva in un particolare momento.
La visualizzazione di una nuova schermata la porterà in cima allo stack mettendo in
uno stato di pausa quelle precedenti.
Quando una Activity termina il proprio lavoro farà in modo di ritornare le eventuali
informazioni raccolte alla precedente, la quale diventerà nuovamente attiva.
In una logica di ottimizzazione delle risorse, è necessario prevedere che una Activity
non visualizzata, possa essere eliminata dal sistema per poi essere eventualmente
ripristinata successivamente.
Il programmatore attraverso alcuni metodi di callback deve gestire i passaggi di stati.
BROADCAST RECEIVER
Ascolta e risponde agli eventi.
Esso ha il ruolo di registrare gli eventi in un pattern pubblicazione/sottoscrizione.
Gli eventi sono rappresentati dalla classe Intent, poi sono mandati in broadcast.
Essi sono mandati agli oggetti che si sono registrati.
L’assp dei Messaggi è una di quelle che usano il broadcast.
Esempio: Se qualcuno mi manda un SMS, alla ricezione Android inserirà l’icona che
indica l’arrivo del messaggio nella Notification Bar. Perché non si sa esattamente
quando l’SMS arriva, Android ha un software che resta in attesa di SMS. All’arrivo il
componente invia in broadcast l’intent sms_received, un altro broadcast receiver,
che riceve l’intent, inizializza un servizio che scaricherà a memorizzerà il messaggio.
CONTENT PROVIDER
Come sopra.
SERVICE
Si ha la necessità di un meccanismo che permetta di mantenere in vita il più possibile
alcuni oggetti (thread) senza correre il rischio che questi vengano eleminati al fine di
una politica di ottimizzazione delle risorse.
Peri i casi in cui un task (non app) deve essere sempre attivo si può utilizzare un
Service.
Gira in background, in modo indipendente da ciò che è eventualmente visualizzato
sul display.
Operazioni long-run.
Interazione con processi remoti.
Esempio: app musiaca e MediaPlaybackService.
EMULATORE
L’ambiente Android mette a disposizione una serie di emulatori istanziabili attraverso
un AVD (Android Virtual Device), che rappresenta una possibile configurazione di cui
un dispositivo reale può essere dotato.
La creazione dell’AVD viene effettuata attraverso un tool chiamato AVD Manager,
che permette di creare diversi emulatori per smartphone, dispositivi wereable, TV e
auto.
Vantaggi:
- Economico;
- Non si necessita del dispositivo;
- L’hardware è riconfigurabile (dimensione scheda SD);
- Modifiche sono isolate nel dispositivo, è meno rischioso.
Svantaggi:
- Lento…molto lento.
- Alcune caratteristiche non sono supportate, ad esempio Bluetooth e usb;
- Alcune caratteristiche variano tra l’emulatore e il dispositivo.
- Non è un dispositivo.
Si possono impostare:
- Velocità network/ latenza;
- Stato batteria;
- Coordinate geografiche.
DEBUGGER
L’ambiente Android mette a disposizione una serie di emulatori
MEMORY LEAK
Java ed Android prevedono l’uso di un garbage collector, ovvero di un processo che,
a intervalli non prevedibili, scandisce la memoria a caccia di oggetti non più utilizzati,
per poterli eliminare.
I problemi si verificano quando un oggetto che dovrebbe essere eliminato rimane in
memoria perché mantenuto in vita da collegamenti diventati inutili, ma comunque
esistenti e vivi.
Questa è la situazione che caratterizza un memory leak.
Può portare a un errore di tipo Out of Memory e che porta inesorabilmente al crash
dell’applicazione, in quanto la memoria viene comunque condivisa da più
applicazioni.
PASSAGGIO DI OGGETTI
Interfaccia Serializable: un oggetto si dice serializzabile se può essere trasformato in
uno stream di byte da cui può essere riconosciuto.
Si tratta della tecnologia che Java utilizza per passare degli oggetti come parametri di
operazioni remote, dove per remoto si intende in esecuzione in un’istanza diversa
dalla Virtual Machine oppure in processi diversi.
Dal punto di vista del linguaggio è serializzabile se implementa l’interfaccia
Serializable
Intent.putExtra(BusStop.keys.ID, busStop)
busStop è una variabile di tipo BusStop che implementa l’interfaccia citata
Per la ricezione basterà usare:
getSerializableExtra(BusStop.keys.ID);
L’interfaccia serializable è poco efficiente in ambito mobile dovuto a un problema di
performance
Per questo motivo, venne introdotta la tecnica di parcelizzazione, rappresentata
dall’interfaccia android.os.Parceable.
Essa permette di ottenere prestazioni migliori, soprattutto nella comunicazione tra
processi.
Un aspetto negativo riguarda la necessità di scrivere codice aggiuntivo che deve
seguire un certo schema che abbiamo implementato nelle nostre classi di modello.
Tale interfaccia prevede la definizione di due operazioni:
- public int describeContents(): restituisce un insieme di flags che permettono di
indicare se il nostro oggetto contiene oggetti da gestire in modo particolare
durante le fasi di parcellizzazione.
- public void writeToParcel(Parcel dest, int flaga): invocate nel momento in cui si
deve trasferire un oggetto; il parametron Parcel rappresenta il contenitore dal
quale andare a scrivere I vari parametric atttraverso una serie di metodi del tipo
writexxx().
FRAGMENT
E’ descritto da particolari specializzazioni dell’omonima classe del package
android.app.
Si tratta di un componente diverso dall’Activity, che consente di gestire delle sotto-
attività non solo per quello che riguarda la loro UI, ma anche lo loro history, quel
meccanismo che permette di mantenere lo stato di navigazione per la gestione del
pulsante Back.
Dopo la creazione dell’istanza Fragment, il metodo invocato dal sistema è onAttach(),
che offre la possibilità di ottenere un riferimento all’Activity contenitore.
Una volta che il Fragment è stato associato a una attività, viene invocato il metodo
onCreate().
In questo metodo si eseguono tutte le operazioni di inizializzazione legate al
componente che qui si traducono nell’assegnazione di un Adapter (componente in
grado di accedere a informazioni memorizzate in una base di dati e di creare delle
View per la loro visualizzazione all’interno di un componente come la ListView).
Il Fragment viene creato e gli viene associato un layout all’interno
dell’implementazione del metodo onCreateView().
Il metodo invocato, successivamente all’associazione della View, è onViewCreated().
LISTFRAGMENT E DIALOGFRAGMENT
Libro.
ACTION BAR
La ActionBar è stata introdotta per permette il posizionamento del brand
dell’applicazione oltre che per dare indicazioni sullo stato della navigazione,
consentendo un accesso alle sue funzionalità più importanti e dirette che necessitano
di essere trovate in modo semplice e veloce.
L’ActionBar è un componente che viene inserito nella gerarchia delle View, ma sena
sovrapporsi a esse.
Il metodo della classe Activity che permette di ottenere l’acceso alla ActionBar si
chiama getActionBar(), nel caso dell’utilizzo delle librerie di supporto si utilizza il
metodo getSupportActionBar().
Nel caso in cui si volesse sottrarre spazio al layout dell’Activity, si può utilizzare il
seguente attributo, che permette di ottenere un’ActionBar che, quando visualizzata,
si sovrappone al layout dell’attività senza portarle via spazio, ma nascondendolo in
parte:
<item name=”android:windowActionBarOverlay”>true</item>.
Le applicazioni non fanno altro che ottenere un riferimento all’ActionBar, invocando I
metodi show() e hide().
E’ possibile inserire delle opzioni all’interno di un’ActionBar.
Le opzioni possono essere visualizzate come azioni dell’ActionBar, attraverso
un’opportuna configurazione in un file delle risorse di tipo menu.
android:showsAction, può avere un valore tra i seguenti:
- always: ci permette di richiedere che vengano sempre e comunque visualizzate
nell’ActionBar;
- never: non verranno mai inserite nell’ActionBar;
- withText: ci permette di richiedere la visualizzazione dell’etichetta anche nel caso
in cui le fosse associata un’immagine;
- ifRoom: ci consente di chiedere al sistema di aggiungere tali opzioni solamente se
c’è abbastanza spazio;
- collapseActionView: indica particolari View e layout per azioni personalizzate.
Queste opzioni vengono create all’interno del metodo;
public boolean onCreateOptionsMenu(Menu menu)
MENU CONTESTUALE
Sono un insieme di opzioni che descrivono azioni che possono essere eseguite su uno
o più oggetti.
I menu contestuali sono di due tipi:
- Floating Context Menu;
- Contextual Action Mode;
Il primo è un menu che compare all’interno di una finestra di dialogo al centro del
display.
Il secondo consiste in una vera e propria personalizzazione dell’ActionBar per la
visualizzazione di un insieme di operazioni da eseguiere su uno o più elementi
selezionati.
Dettagli libro.
TOOLBAR
La ActionBar è un componente, che fa parte della gerarchia di View legate a una
Activity e non per esempio a un Fragment.
A differenza della ActionBar, una Toolbar può essere inserita in un qualunque
layout e gestita da Activity o da un Fragment.
Questo aspetto rende la Toolbar un componente più versatile rispetto a un’ActionBar
che può essere utilizzata al suo posto.
Una Toolbar dispone dei seguenti elementi che possono essere presenti oppure no e
che sono caratteristici di una Toolbar:
- Button di navigazione;
- Una immagine come logo;
- Un titolo e un sottotitolo;
- Delle custom View;
- Delle azioni associate.
Dettagli libro.
VIEW E LAYOUT
Le diverse schermate, descritte da altrettante Activity e Fragment, contengono dei
componenti che tipicamente sono dei Button per l’interazione con l’utente, degli
EditText per l’inserimento di informazioni testuali e delle TextView per la
visualizzazione delle stesse.
Si tratta di componenti descritti da altrettante specializzazione della classe View, che
contiene tutte le informazioni comuni a ogni elemento grafico con cui l’utente
interagisce.
L’interfaccia grafica può essere descritta attraverso un approccio dichiarativo,
definizione di un documento XML (cioè documento di layout); o un approccio
imperativo cioè descrizione della UI attraverso righe di codice.
L’XML a differenza del codice Java, ha diversi vantaggi:
- Attraverso il layout editor è possibile avere subito un feedback sul risultato.
- Sono risorse che possono essere qualificate (per esempio rispetto a diversi
orientamenti del display) utilizzando l’apposito meccanismo messo a disposizione
dalla piattaforma.
- All’Activity non viene anche data la responsabilità di definire l’interfaccia, ma
solamente quella di gestire gli eventi sui diversi componenti e di fungere da
controller in un contesto MVC.
- Lo stesso documento di layout potrebbe essere riutilizzato per la definizione di
altre attività o parti di esse.
Model View Controller (MVC) è un’architettura di sviluppo che consente di attuare
una suddivisione di responsabilità tra chi è deputato alla gestione dei dati (il Model),
alla loro visualizzazione (la View) e al mapping tra gli eventi sulla View e le operazioni
sul Model (il Controller).
Il metodo setContentView() utilizza l’overload, che prevede come parametro
l’identificativo della risorsa di tipo layout:
setContentView(R.layout.buttons_layout);
findViewById() per ottenere un riferimento a una particolare View dato il suo id;
l’operazione di cast serve in quant oil metodo findViewById() vale per una qualunque
View che corrisponde al tipo di dato restituito.
La classe ViewGroup anch’essa una specializzazione della classe View, con la
fondamentale proprietà di poter aggregare altre View.
Attenzione: questo significa che un ViewGroup potrà aggregare un insieme di altre
View, alcune delle quali potranno essere a loro volta dei ViewGroup che aggregano
altre View e così via.
E’ possibile creare un albero di componenti da poter applicare a ciascuno di essi, in
modo ricorsivo, delle operazioni come può essere quella di visualizzazione.
Composite Pattern (immagine sul libro pag 274)
Per quanto riguarda il posizionamento, vedi libro pag. 276.
LINEAR LAYOUT
Il LinearLayout, permette di disporre le View in esso contenute su una singola riga o
colonna a seconda della sua proprietà orientation.
Per specificare se disporre i componenti su una riga o colonna si può utilizzare
l’attributo:
android:layout_orientation
Il quale può assumere i valori horizontal e vertical.
La stessa informazione può essere specificata attraverso il metodo
public void setOrientation(int orientation).
con I due possibili valori rappresentati dale costanti statiche HORIZONTAL e VERTICAL
della classe LinearLayout.
La classe LinearLayout estende la classe ViewGroup che sappiamo definre una classe
interna di nome ViewGroup.LayoutParams per gli attributi che le View contenute
dovranno specificare.
Si tratta di quelle relative alle dimensioni, alle quali la classe LinearLayout, attraverso
la definizione della classe interna LinearLayout.LayoutParams, aggiunge quelle
relative a gravità (gravity) e peso (weight).
layout_weiht indica il peso che una View ha rispetto all’occupazione dello spazio
disponibile in un particolare momento.
Si esprime tramite un valore numerico che indica in quale proporzione una View
occuperà tutto lo spazio che ha a disposizione rispetto alle altre.
Uno stesso valore di peso per le due View consente di dividere lo spazio in parti
uguali.
La posizione in cui le View contenute vengono inserite a partire dal vertice superiore
sinistro e poi la direzione relativa all’orientamento, viene descritta dall’attributo
android:layout_gravity.
RELATIVE LAYOUT
Consente di specificare la posizione di ogni View relativamente a quella del container
o di altre.
Attraverso l’attributo android:layout_alignParentRight a true stiamo comunicando
l’intenzione di allinearlo a destra con il proprio contenitore.
Attraverso l’attributo android_layout_toRight stiamo dicendo che questo
componente dovrà stare alla destra di quello dell’id specificato dal corrispondente
valore.
FRAME LAYOUT
Il FrameLayout consente di avere un controllo sulla visualizzazione delle view che
contiene, fornendo gli strumenti per visualizzarne o nasconderne alcune.
DRAWABLE
Vedi libro, pag. 293.
ASSENTS E FONT
Vedi libro, pag. 305.
CREAZIONE DI UN COMPONENTE PERSONALIZZATO
Componente personalizzato per la scelta della data.
Due approcci diversi.
Il primo ci permetterà di creare il componente attraverso la definizione di un
particolare layout.
Il secondo approccio utilizzerà invece gli strumenti di più basso livello, come quelli
che ci permettono di scrivere sul Canvas del componente.
LISTVIEW E ADAPTER
Un’Adapter è una particolare interfaccia che descrive un’astrazione la cui
responsabilità è quella di disaccoppiare la modalità di acquisizione dei dati, dalla loro
visualizzazione.
Spesso si fa un’analogia fra l’Adapter e il DAO (Data Access Object), in quanto si tratta
di pattern con caratteristiche molto simili.
La differenza sostanziale sta nel fatto che, mentre un DAO si occupa solo di dati, un
Adapter ne fornisce anche le possibili rappresentazioni.
Un Adapter è qualunque componente la cui responsabilità è quella di reperire
informazioni da una base di dati e di fornire, per ciascuna di esse, una
rappresentazione attraverso una particolare specializzazione della classe View, che
sappiamo essere la generalizzazione di ogni elemento della UI da inserire in
un’Activity.
Un ViewGroup è una particolare View con responsabilità di layout.
Una particolare specializzazione di ViewGroup potrebbe aggregare, e quindi
visualizzare, in modo diverso un insieme di View che gli vengono fornite da un
particolare Adapter.
Stiamo parlando della classe AdapterView che implementa tutta la logica di
collaborazione tra un ViewGroup e un Adapter.
La ListView è una specializzazione della classe AdapterView che visualizza le View
fornite da un Adapter secondo una modalità a lista che si può far scorrere
verticalmente.
IL PATTERN HOLDER
Vedi libro, pag.373.
RECYCLERVIEW
La Listview è un componente che dal punto di vista object oriented, si è rivelato poco
coeso.
La coesione è una caratteristica di un oggetto di gestire più aspetti che in un certo
senso non sono collegati tra loro.
Questo ha lo svantaggio che la modifica in uno di questi aspetti comporta delle
modifiche anche nel codice che dovrebbe gestire aspetti diversi.
Dalla versione Lollipop (Android 5.0) Google ha deciso di implementare una serie di
componenti più coesi.
Il principale di questi componenti è proprio quello descritto dalla classe
RecyclerView, la cui responsabilità è quella di riciclare View al fine di una migliore
gestione delle risorse.
Riciclare significa, ottenere migliori performance, in quanto non dobbiamo ripetere
operazioni di inflate che sono molto pesanti; inoltre si ha un migliore utilizzo della
memoria.
Ma se il RecyclerView ha responsabilità del riciclo, chi ha la responsabilità di creare le
varie View da visualizzare?
Anche in questo caso esiste il concetto di Adapter, in questo caso però, le View
vengono gestite in modo esplicito da quello che si chiama ViewHolder.
Le RecyclerView obbligano a creare ViewHolder che mantengono i riferimenti alle
View nel layout associato a ciascun elemento del modello.
Una RecyclerView è in grado di riciclare istanze di ViewHolder gestite da un
particolare Adapter in grado di accedere ai dati.
La successiva responsabilità è quella di posizionare questi elementi all’interno dello
spazio disponibile.
Questa è la responsabilità del LayoutManager.
LAYOUTMANAGER
Il LayoutManager è responsabile dell’esecuzione delle fasi di measure e layout dei
componenti che la RecyclerView dovrà gestire.
La particolare implementazione di LayoutManager deve inoltre stabilire quando una
particolare View (o relativo ViewHolder) possa essere riciclata quando non più
visibile.
Dettagli libro, pag. 393.
ITEMDECORATION
Vedi libro, pag. 402.
LE CARDVIEW
Viene utilizzata per gestire dati molto diversi tra loro.
E’ un layout che permette di aggiungere a un particolare contenuto un aspetto più
vicino alle specifiche Material Design e quindi con bordi arrotondati e utilizzo di
elevation, con conseguente ombra.
Si tratta di un caso particolare di FrameLayout che decora il suo contenuto
aggiungendo un aspetto Material.
SQLITE
Vedi libro, pag. 490.
SQULITEOPENHELPER
Vedi libro, pag. 521.
UTILIZZO DI CONTENTPROVIDER
Esistono determinati tipi di risorse che, per la natura stessa di Android, dovrebbero
essere condivise, per esempio l’insieme dei contatti.
Per questo motivo la piattaforma ha ideato dei componenti che si chiamano
ContentProvider, i quali permettono di accedere a un particolare insieme di
informazioni attraverso un’interfaccia che ricorda da vicino i servizi REST
(REpresentational State Transfer).
A ciascun ContentProvider possono essere associati uno o più Uri del tipo:
content://<authority>/path
Mentre la parte authority caratterizza in modo univoco il particolare
ContentProvider, la parte path consente di specificare il tipo di risorsa in esso
memorizzata.
I ContentProvider sono di fondamentale importanza anche nel meccanismo di
IntentResolution, ovvero quell’insieme di regole che permette di individuare il
particolare componente in grado di soddisfare un particolare intent.
E’ infatti responsabilità del ContentProvider indicare il particolare content type
associato a un determinato URI.
MULTITHREADING E SERVIZI
THREAD
Per descrivere cos’è un thread (thread of control), possiamo partire definendo un
algoritmo come un insieme di operazioni, spesso descritte con linguaggio naturale,
che permettono la risoluzione di un particolare problema.
Il Thread of Control gestisce infatti in modo indipendente parti diverse di uno stesso
oggetto.
Un oggetto può essere scritto utilizzando diversi linguaggi di programmazione, dando
origine ai programmi.
Concetto di processo, ovvero di esecuzione di un particolare programma.
Due processi, in esecuzione di uno stesso programma, sono caratterizzati dal fatto di
utilizzare ciascuno una propria area di memoria, e quindi si possono considerare
indipendenti uno dall’altro anche se in esecuzione nello stesso momento.
In diversi ambiti può essere utile estendere il concetto di “esecuzione simultanea”
anche alle diverse parti di una stessa applicazione.
In questo caso non si parla di processo, ma ti thread, caratterizzato dal fatto di
condividere con altri le stesse aree di memoria, richiedendo strumenti che
consentono di mantenere l’integrità dei dati condivisi.
La creazione di un normale thread in Android avviene utilizzando due modi diversi:
- estendere la classe Thread;
- implementare l’interfaccia Runnable.
Nel primo caso è sufficiente estendere la classe Thread con l’override del metodo
run(), che contiene la logica relativa alle operazioni che dovranno essere eseguite in
modo concorrente in corrispondenza dell’esecuzione del metodo start().
Un thread termina la propria esecuzione nel momento in cui il metodo run() giunge a
completamento .
Terminata l’esecuzione, un thread diventa una normale istanza, che può mantenere il
proprio stato, eseguire operazioni, ma non potrà più essere riavviata attraverso una
nuova esecuzione di start().
Il corpo del thread, ovvero le operazioni da eseguire in modo concorrente, vengono
implementate all’interno del metodo run().
Rileviamo poi l’utilizzo della variabile booleana running, che serve per interrompere
l’esecuzione del metodo run() facendo terminare il ciclo while solitamente presente
in oggetti di questo tipo.
Il secondo meccanismo utilizzato consiste nella creazione di un’istanza della classe
Thread cui viene però passata un’implementazione dell’interfaccia Runnable, che
descrive proprio l’unica operazione che ci interessa.
L’implementazione dei metodi start() e stop() permette alla stessa istanza di essere
riavviata più volte.
Al costruttore seguente si può passare il riferimento a una qualunque classe che
implementi l’interfaccia Runnable.
public Thread (Runnable runnable)
I thread di questo tipo sono i primi a essere eliminati dall’ambiente quando servono
risorse.
Qualora si avesse la necessità di eseguire operazioni in background per lungo tempo,
Android mette a disposizione i Service.
Spesso i thread vengono utilizzati per accedere a risorse esterne per l’acquisizione di
informazioni che poi dovranno essere visualizzate attraverso la UI.
Serve un meccanismo che consenta l’invio di informazioni alla UI senza impattare
sulla reattività Handler e Looper.
HANDLER E LOOPER
I problemi si hanno quando si tratta di thread con la responsabiltà di procurare
informazioni da visualizzare all’interno di componenti grafici contenuti in un’Activity
o gli Intent Receiver.
Per risolvere questo problema, Android fornisce un piccolo framework che semplifica
l’interazione tra thread diversi di una stessa applicazione e quindi anche l’interazione
tra lo UIThread e un thread da noi creato, che si indica come Worker Thread.
Alla base di queste API ci sono le seguenti classi:
- Handler;
- MessageQueue;
- Message.
A ciascun thread, Android associa una particolare MessageQueue che non è altro
che una coda di messaggi descritti da istane della classe Message.
Un messaggio è una specie di transfer object, cioè un oggetto in grado di
memorizzare informazioni al fine di poterle trasferire in un’unica chiamata.
E’ una classe che implementa l’interfaccia Parcelable.
Per poter eseguire una particolare azione in un determinato thread basterà inserire
nella corrispondente cosa un messaggio che ne incapsuli le informazioni.
L’oggetto responsabile della ricezione dei messaggi dovrà essere un oggetto
associato al thread di destinazione.
Si tratta di una particolare istanza della classe Handler che riceve ed elabora i
messaggi della MessageQueue associati allo stesso thread nel quale l’Handler stesso
è creato.
In pratica, i messaggi contenenti informazioni da utilizzare per l’aggiornamento dei
componenti della UI dovranno essere ricevuti da un’istanza della classe Handler
creata all’interno del Main Thread.
Ultimo passo, relativo alla creazione e invio del messaggio da parte di un Worker
Thread.
E’ sufficiente che quest’ultimo abbia il riferimento all’Handler per chiedergli
un’istanza del messaggio relativo alla sua coda.
LA CLASSE AsynTask
Thread e task, sono due concetti legati tra loro, ma distinti.
Un thread è una successione di operazioni che agiscono su informazioni che
possono essere condivise con altri thread.
Un thread potrebbe comunque essere indefinito; un esempio è il thread relativo a un
ServerSocket che rimane in ascolto delle richieste dei client per un tempo indefinito.
Un task è invece una successione di operazioni che prima o poi si completa e che di
solito produce un risultato.
L’operazione di download è rappresentata da un task.
Si tratta comunque di due concetti correlati, in quanto i task vengono eseguiti
all’interno di particolari thread.
Java mette a disposizione due interfacce diverse: Runnable per i thread e Callable per
i task.
Ora abbiamo a che fare con task; significa che attraverso la nostra implementazione
di AsynTask, ci aspettiamo di ottenere un risultato.
Anche il significato della funzione stop è diverso, in quanto non rappresenta
l’interruzione temporanea, ma l’annullamento o cancellazione del task.
Non sarà possibile fermare temporaneamente il task per poi farlo proseguire.
AsynTask è una classe generica caratterizzata da ben tre diversi tipi di dato.
Il primo un Integer, è il tipo dei parametri di input dei task.
Il secondo è ancora un Integer e rappresenta il tipo di valore che potrà caratterizzare
il progredire del task.
Il terzo è quello del risultato che il nostro task dovrà produrre.
Quali sono i problemi che una classe di questo tipo intende risolvere?
- Eseguire un task in background.
- Notificare l’avvio e la fine del task all’interno del thread principale.
- Notificare il progredire del task attraverso l’interazione con lo UI thread.
- Gestire la cancellazione del task.
La classe AsynTask ci fornisce poi gli strumenti per gestire in qualche modo l’avvio e
la conclusione del task attraverso due metodi:
onPreExecute() e onPostExecute().
Il primo viene invocato all’avvio del task, mentre il secondo al completamento dello
stesso.
NOTIFICATION SERVICE
Vedi libro, pag. 575.
SERVICE
Android non garantisce che una particolare attività venga sempre mantenuta in vita,
specialmente se non è visualizzata in un particolare momento.
Questo fa sì che l’Activity non sia il luogo migliore dove descrivere operazioni di lunga
durata da eseguire in background.
A tale scopo, Android fornisce un particolare componente che si chiama Service e che
ha un trattamento particolare che lo preserva dall’essere eliminato dal sistema.
Un particolare Service vuole essere la soluzione di due casi ben precisi.
Il primo è quello che permette l’esecuzione di un task di lunga durata in modo
indipendente dal ciclo di vita del componente che lo ha avviato.
Questo scenario è il primo che trova la propria soluzione nell’utilizzo di un Service che
si dice Started.
Lo scenario prevede che l’unico in grado di sapere se il task sia stato completato o
meno è proprio il servizio che sarà anche responsabile della sua eliminazione.
Il secondo scenario prevede che questo esponga un’interfaccia in ambito enterprise
definiremo remota, in quanto in esecuzione di un processo diverso da quello del
client.
Questo tipo di servizi viene indicato come Bound.
E’ il client che sa quando inizia e quando finisce l’utilizzo delle operazioni messe a
disposizione del Service.
Un aspetto consiste nel fatto che una stessa istanza di service potrebbe essere sia
Started e anche Bounded.
Se un servizio è già attivo a seguito di una richiesta come Started, e un client ne
richiede l’utilizzo attraverso il metodo bindService(), non viene creata una nuova
istanza, ma viene utilizzata quella già presente.