relazione progmobile

This commit is contained in:
Francesco Mecca 2020-04-20 16:58:51 +02:00
parent a0dc9ab579
commit 8dda87f54a

View file

@ -39,3 +39,53 @@ La nostra applicazione ha come interesse primario quello di attrarre questa comu
Gli utenti possono condividere la loro vasta libreria musicale con più utenti e fare streaming dei propri file audio in diversi formati in base alle esigenze e alla banda disponibile. Gli utenti possono condividere la loro vasta libreria musicale con più utenti e fare streaming dei propri file audio in diversi formati in base alle esigenze e alla banda disponibile.
Il catalogo musicale è nel pieno controllo dell'utente che andrà a gestirlo con gli strumenti che già utilizzava. Il catalogo musicale è nel pieno controllo dell'utente che andrà a gestirlo con gli strumenti che già utilizzava.
Il server con il quale l'applicazione comunica supporta la lettura dei metadati dei file e del database di MPD. Il server con il quale l'applicazione comunica supporta la lettura dei metadati dei file e del database di MPD.
# Implementazione e funzionalità
## Schema di navigazione di base
All'avvio l'applicazione richiedere l'inserimento delle credenziali di accesso al server (ip, porta, username, password) da parte dell'utente. Tali credenziali vengono memorizzate per poter essere riutilizzate al prossimo avvio.
Una volta effettuato il login si potrà navigare la libreria musicale.
La navigazione è gestita da un Fragment parametrizzato dalla modalità scelta per la navigazione, ossia genere, artista o album.
La navigazione è arricchita dalla visualizzazione delle copertine e delle foto degli artisti, scaricate interattivamente.
Una volta selezionata una canzone questa verrà messa in riproduzione. Dal Fragment è possibile selezionare la qualità di riproduzione, ovvero High Quality, Medium Quality e Low Quality. Inoltre, nel caso si stesse ascoltando una canzone, è possibile visualizzare le lyrics.
Durante l'ascolto è possibile aggiungere il brano in riproduzione alla playlist "Favourites".
Le altre playlists sono visualizzabili attraverso le schermate di navigazione e possono essere modificate tramite apposito menù.
Infine è possibile condividere la canzone in ascolto attraverso il bottone "condividi" inviando un messaggio di testo.
## Scelte tecniche
### Riproduzione in streaming
La riproduzione in streaming presenta notevoli difficoltà se abbinata al transcoding on the fly, ovvero la riduzione di qualità di un brano in alta definizione mentre lo si sta ascoltando. La riproduzione di un sorgente tramite protocllo HTTP è fornita dalla classe MediaPlayer del framework Android. Durante la riproduzione la dimensione del file è in continua crescita poiché la dimensione del file sul server è proporzionale alla percentuale di file del quale è già stato compiuto il transcoding. Inoltre il transcoding effettuato tramite Variabile Bit Rate per definizione non permette di conoscere la dimensione finale del file. Per permettere all'utente di fare seek della traccia audio, Apollon interroga la classe MediaPlayer sulla quantità di buffer disponibile e interroga il server sullo stato del transcoding. Attraverso queste due informazioni Apollon effettua il seek con precisione. Quando il seek non è disponibile per mancanza di buffer, la barra di riproduzione viene leggermente oscurata.
### Interazione col dispositivo
Quando un brano è in riproduzione viene mostrata la copertina come wallpaper del blocco schermo.
Inoltre la riproduzione si ferma se vengono staccate le cuffie o se arriva una chiamata.
L'output di Apollon viene ridotto per qualche istante nel caso sopraggiunga una notifica.
### Servizi di terze parti
Le lyrics vengono fornite da ChartLyrics tramite api web in formato XML.
Le immagini sono fornite da WikiData e scaricate attraverso la libreria Picasso che si occupa di fare caching talora necessario.
### Pattern architetturali
Nel codice risalta un notevole utilizzo di pattern architetturali, alcuni comuni a Java e Kotlin, altri specifici di Kotlin e della programmazione funzionale. Inoltre abbiamo seguito differenti tecniche di programmazione e riuso specifici del framework Android.
All'interno dei pattern tipici della programmazione ad oggetti compaiono:
* Adapters: usato per adattare l'interfaccia di una classe ad un'altra. Nel nostro caso è stato usato questo pattern per le classi che forniscono la logica e la visualizzazione all'interno dei fragments.
* Builder: pattern creazionale utilizzato per l'instanziazione step by step di oggetti complessi. Fra le varie classi in cui usiamo questo pattern, la più importante sono quelle per la gestione dei metadati del brano in riproduzione e per l'instanziazione del mediaplayer.
* Events: gli eventi sono oggetti instanziati in risposta a degli input esterni (quali rete o utente) e vengono gestiti in maniera asincrona da differenti funzioni. Vengono utilizzati nella nostra applicazione per gestire la UI e gli eventi di rete relativi lla riproduzione in streaming.
Kotlin ci ha permesso da un lato di usare con più facilità e in maniera meno verbosa dei pattern tipi della programmazione ad oggetti, in particolare:
* Singleton: pattern che restringe l'instanziazione di una classe ad un solo oggetto. Utilizzata per la connessione al server e la gestione delle credenziali (che a sua volta è un adapter per SharedPreferences).
* Companion Object: un singleton che ha accesso ai membri privati degli oggetti instanziati dalla classe compagno (ovvero della classe all'interno del quale è dichiarato). Ne facciamo uso per la creazione delle instanze dei fragments.
* Sum Types: pattern tipicamente funzionale in cui una struttura dati può contenere diversi tipi predefiniti. Abbiamo modellato i sum types in Kotlin attraverso l'uso delle **sealed class** che ci ha permesso di codificare lo stato del programma attraverso i tipi.
* Pattern Matching: pattern estremamente correlato all'uso dei sum types. Attraverso il pattern matching siamo sicuri che in ogni branch del nostro codice abbiamo preso in considerazione ogni stato possibile. L'uso di assert(false) ci permette di asserire quali tipi non devono raggiungere quella sezione di codice.
Infine nella nostra codebase abbiamo fatto un uso estensivo delle componenti del framework Android, in particolare:
* Fragments: componenti che incapsulano il comportamente e l'UI di una singola activity. Ci ha permesso di riciclare della logica complessa e adattare le componenti grafiche a diversi layout.
* Services e AsyncTasks: per fare in modo che il thread principale non si blocchi abbiamo utilizzato dei background service. In particolare ogni operazione bloccante è incapsulata dentro un AsyncTask che ne modella il comportamento in base al risultato.