Crea un'app Player musicale con Anko

Cosa starai creando

Un buon approccio per diventare abili in un nuovo linguaggio o libreria di programmazione è cercare di creare qualcosa di utile con esso. Nel mio tutorial su come semplificare lo sviluppo di Android con Anko, ho introdotto la lingua e le funzioni di supporto specifiche di Anko. Anche se sono sicuro che li hai trovati impressionanti, potresti essere ancora preoccupato di utilizzarli in app grandi e complesse, dal momento che sono così diverse dalle tradizionali classi e metodi Android.

Quindi, oggi useremo Kotlin e Anko per creare un'app per music player per Android, una che possa selezionare e riprodurre automaticamente brani casuali dal dispositivo dell'utente. La sua interfaccia utente abbastanza complessa, che avrà diversi widget che interagiscono tra loro, dovrebbe aiutarti a capire meglio come funzionano le app Anko.

Prerequisiti

Per poter seguire questo tutorial passo passo, avrai bisogno di:

  • l'ultima versione di Android Studio
  • un telefono o tablet con Android 5.0 o versioni successive
  • e alcuni album MP3

Se non lo hai già fatto, leggi il seguente tutorial prima di procedere:

1. Creazione di un nuovo progetto

Avvia Android Studio e premi il tasto Avvia un nuovo progetto Android Studio pulsante per avviare la procedura guidata di creazione del progetto. Nella schermata successiva, dai un nome alla tua app e assicurati che il Include il supporto Kotlin il campo è selezionato.

Successivamente, seleziona API di livello 21 o versione successiva e scegli Attività vuota modello. Poiché non avremo bisogno di alcun file XML di layout, assicurati di deselezionare l'opzione Genera file di layout campo.

Finalmente, premi finire per creare il progetto.

2. Aggiunta di dipendenze

Per aggiungere Anko al progetto, aggiungi quanto segue implementazione dipendenza nel build.gradle file del App modulo:

implementazione 'org.jetbrains.anko: anko: 0.10.1'

Useremo le coroutine di Kotlin per eseguire alcune operazioni in modo asincrono, quindi aggiungiamo una dipendenza per il prossimo.

implementazione 'org.jetbrains.kotlinx: kotlinx-coroutines-android: 0.19.3'

Il nostro lettore musicale, poiché riproduce le canzoni in modo casuale, necessita di un elenco di tutti i brani disponibili sul dispositivo. Per evitare di implementare la logica per creare un elenco di questo tipo, aggiungi DroidMelody, una libreria che ho creato appositamente per questo tutorial, come ultima dipendenza. Poiché è approvato e pubblicato da jcenter, il repository predefinito di Android Studio, aggiungendolo non è diverso dall'aggiunta di altre dipendenze.

implementazione 'com.progur.droidmelody: droidmelody: 1.0.2'

Inoltre, avremo bisogno di alcune icone relative ai media, quindi apri Vector Asset Studio. Al suo interno, vai al AV categoria e scegli le icone con i simboli play, pause e shuffle.

A questo punto, i seguenti file dovrebbero essere presenti in res / drawable cartella del tuo progetto:

  • ic_play_arrow_black_24dp.xml
  • ic_pause_black_24dp.xml
  • ic_shuffle_black_24dp.xml

3. Richiesta di permessi

La maggior parte degli utenti memorizza le proprie canzoni su un supporto di memorizzazione esterno. Pertanto, su dispositivi con Android Marshmallow o versioni successive, sarà necessario richiedere esplicitamente READ_EXTERNAL_STORAGE permesso in fase di esecuzione.

Prima di richiedere l'autorizzazione, tuttavia, è necessario verificare se l'utente lo ha già concesso. Puoi farlo chiamando il ContextCompat.checkSelfPermission () metodo all'interno del onCreate () metodo della tua attività. Se il permesso non è stato concesso, puoi richiederlo chiamando il ActivityCompat.requestPermissions () metodo.

Di conseguenza, aggiungere il seguente codice:

if (ContextCompat.checkSelfPermission (this, Manifest.permission.READ_EXTERNAL_STORAGE)! = PackageManager.PERMISSION_GRANTED) // Richiedi il permesso ActivityCompat.requestPermissions (this, arrayOf (Manifest.permission.READ_EXTERNAL_STORAGE), 0) else // Inizio creando l'interfaccia utente createPlayer ()

Nota che il codice sopra chiama un metodo chiamato createPlayer () se il permesso è già stato concesso. Creeremo questo metodo nel prossimo passaggio.

Dopo aver chiesto il permesso, è necessario ignorare il onRequestPermissionsResult () metodo dell'attività per determinare se l'utente ha accettato la richiesta. Se lo facessero, dovresti chiamare di nuovo il createPlayer () metodo. In caso contrario, visualizza un messaggio di errore utilizzando Anko longToast () aiutante e chiudi l'app.

override fun onRequestPermissionsResult (requestCode: Int, permessi: Array, grantResults: IntArray) super.onRequestPermissionsResult (requestCode, permissions, grantResults) if (grantResults [0] == PackageManager.PERMISSION_GRANTED) createPlayer () else longToast ("Autorizzazione non concessa. Chiusura.") finish () 

4. Recupero di tutte le canzoni

È giunto il momento di definire il createPlayer () metodo, che sarà responsabile sia dell'aspetto che della funzionalità della nostra app.

divertimento privato createPlayer () // Altro codice qui

All'interno del metodo, la prima cosa che devi fare è generare un elenco di tutti i brani disponibili sul dispositivo. Poiché questo è, come ci si potrebbe aspettare, un'operazione potenzialmente di lunga durata, è possibile avviarla in una nuova coroutine utilizzando il comando async () funzione.

All'interno della coroutine, crea una nuova istanza di DroidMelody SongFinder classe e chiama il suo preparare() metodo, che utilizza il risolutore del contenuto della tua attività per trovare effettivamente tutti i brani e inserirli in un elenco chiamato tutte le canzoni. Una volta completato il metodo, puoi semplicemente tornare tutte le canzoni dalla coroutine. Il seguente codice mostra come:

val songsJob = async val songFinder = SongFinder (contentResolver) songFinder.prepare () songFinder.allSongs

La suddetta coroutine funziona in modo asincrono. Per attendere il risultato, è necessario chiamare il attendere () metodo all'interno di un'altra coroutine creata usando il lanciare() funzione. Poiché utilizzeremo il risultato per creare l'interfaccia utente della nostra app, la nuova coroutine dovrebbe essere eseguita sul thread dell'interfaccia utente. Questo è specificato passando kotlinx.coroutines.experimental.android.UI come argomento a lanciare().

launch (kotlinx.coroutines.experimental.android.UI) val songs = songsJob.await () // Più codice qui

Ora hai un elenco di Canzone oggetti. Ogni Canzone oggetto avrà diversi dettagli importanti sulla canzone a cui fa riferimento, come il titolo, l'artista, la copertina dell'album e l'URI.

5. Creazione di un componente Anko

Per impostazione predefinita, il DSL di Anko è direttamente disponibile solo all'interno di onCreate () metodo di un'attività. Per essere in grado di usarlo all'interno del createPlayer () metodo, puoi o dipendere dal UI () funzione o creare un nuovo componente Anko. In questo tutorial andremo con quest'ultimo approccio perché è più riutilizzabile.

Per creare un nuovo componente Anko, devi estendere l'abstract AnkoComponent classe e scavalca il suo createView () metodo, all'interno del quale si avrà accesso alla DSL.

val playerUI = object: AnkoComponent override fun createView (ui: AnkoContext) = con (ui) // codice DSL qui

6. Definizione dell'interfaccia utente

Poiché la nostra app è un lettore musicale casuale, e non è in grado di funzionare con le playlist, avrà un'interfaccia utente leggermente anticonvenzionale. Ecco i widget visibili che conterrà:

  • un ImageView widget per visualizzare le copertine degli album del brano attualmente in riproduzione
  • un ImageButton widget che consente all'utente di mettere in pausa o riprendere la canzone
  • un ImageButton widget che consente all'utente di scegliere un'altra canzone a caso
  • un TextView widget per visualizzare il titolo del brano
  • un TextView widget per visualizzare il nome dell'artista del brano

Di conseguenza, aggiungere i seguenti campi al componente Anko:

var albumArt: ImageView? = null var playButton: ImageButton? = null var shuffleButton: ImageButton? = null var songTitle: TextView? = null var songArtist: TextView? = null

Inoltre, avremo bisogno di un RelativeLayout e un paio di LinearLayout contenitori per posizionare i widget di cui sopra e stabilire relazioni tra loro. Il seguente diagramma mostra la gerarchia della vista che verrà creata successivamente:

Perché il RelativeLayout il widget si trova nella radice della gerarchia della vista, devi prima crearlo aggiungendo il seguente codice all'interno della createView () metodo del componente Anko:

relativeLayout backgroundColor = Color.BLACK // Altro codice qui

Nota che abbiamo usato il colore di sfondo proprietà del widget per dargli un colore nero. Useremo diverse proprietà in questo tutorial per migliorare l'aspetto della nostra app. Sei libero di cambiare i loro valori per soddisfare le tue preferenze.

Dentro il RelativeLayout widget, aggiungi il ImageView widget per l'arte dell'album. Dovrebbe occupare tutto lo spazio disponibile sullo schermo, quindi utilizzare lparams () metodo dopo averlo aggiunto e passato il partita genitore costante ad esso due volte, una volta per la larghezza e una volta per l'altezza. Ecco come:

albumArt = imageView scaleType = ImageView.ScaleType.FIT_CENTER .lparams (matchParent, matchParent)

Il lparams () metodo, come suggerisce il nome, consente di specificare i parametri di layout che dovrebbero essere associati a un widget. Usandolo, puoi specificare rapidamente dettagli come i margini che un widget dovrebbe avere, le sue dimensioni e la sua posizione.

Quindi, crea un LinearLayout widget con un orientamento verticale chiamando il verticalLayout () funzione e aggiungere il TextView widget ad esso. Il layout deve essere posizionato nella parte inferiore dello schermo, quindi è necessario chiamare il alignParentBottom () funzione mentre si specificano i suoi parametri di layout.

verticalLayout backgroundColor = Color.parseColor ("# 99000000") songTitle = textView textColor = Color.WHITE typeface = Typeface.DEFAULT_BOLD textSize = 18f songArtist = textView textColor = Color.WHITE // Più codice qui .lparams ( matchParent, wrapContent) alignParentBottom ()

Allo stesso modo, crea il LinearLayout widget con un orientamento orizzontale chiamando il LinearLayout () funzione, e aggiungere i due ImageButton widget ad esso. Assicurati di usare il imageResource proprietà dei pulsanti per specificare le icone da visualizzare. Il seguente codice mostra come:

linearLayout playButton = imageButton imageResource = R.drawable.ic_play_arrow_black_24dp onClick playOrPause () .lparams (0, wrapContent, 0.5f) shuffleButton = imageButton imageResource = R.drawable.ic_shuffle_black_24dp onClick playRandom () .lparams (0, wrapContent, 0.5f) .lparams (matchParent, wrapContent) topMargin = dip (5)

È possibile vedere che il codice precedente ha gestori di eventi click per entrambi ImageButton widgets. All'interno dei gestori, ci sono chiamate a due metodi denominati in modo intuitivo: playOrPause () e visualizzarloRandom (). Li creeremo nei prossimi passaggi.

A questo punto, abbiamo finito di definire l'aspetto della nostra app. 

7. Riproduzione di brani

La nostra app non è ancora in grado di riprodurre alcuna musica. Risolviamolo creando il file visualizzarloRandom () metodo.

fun playRandom () // Altro codice qui

Useremo un'istanza di Media Player classe per suonare la musica. È una risorsa piuttosto costosa e dovrebbe essere rilasciata quando l'utente chiude l'app. Pertanto, deve essere definito come un campo dell'attività - e non il componente Anko - e rilasciato all'interno di OnDestroy () metodo dell'attività.

private var mediaPlayer: MediaPlayer? = null override fun onDestroy () mediaPlayer? .release () super.onDestroy ()

Dentro il visualizzarloRandom () metodo, ora possiamo scegliere una canzone a caso dalla lista di canzoni che abbiamo generato in precedenza semplicemente mischiando la lista e selezionando il primo elemento. Questo approccio non è molto efficiente, ma è molto conciso.

Collections.shuffle (canzoni) val song = songs [0]

È ora possibile inizializzare il lettore multimediale con l'URI della nuova canzone scelta. Inoltre, utilizzare il setOnCompletionListener () metodo per assicurarsi che una nuova canzone casuale inizi a suonare non appena il brano corrente è completato.

mediaPlayer? .reset () mediaPlayer = MediaPlayer.create (ctx, song.uri) mediaPlayer? .setOnCompletionListener playRandom ()

Il contenuto del ImageView e TextView anche i widget devono essere aggiornati per visualizzare i dettagli associati alla nuova canzone.

albumArt? .imageURI = song.albumArt songTitle? .text = song.title songArtist? .text = song.artist

Infine, per iniziare effettivamente a suonare la canzone, puoi chiamare il inizio() metodo del lettore multimediale. Ora sarebbe anche il momento giusto per aggiornare il ImageButton widget per cambiare l'icona "riproduci" in un'icona "pausa".

mediaPlayer? .start () playButton? .imageResource = R.drawable.ic_pause_black_24dp

8. Pausa e ripresa

In un passo precedente, abbiamo chiamato un metodo chiamato playOrPause () all'interno del click-handler di uno dei ImageButton widgets. Definirlo come un altro metodo del componente Anko.

fun playOrPause () // Altro codice qui

La logica che devi implementare all'interno di questo metodo dovrebbe essere abbastanza ovvia. Se il lettore multimediale sta già suonando una canzone, che puoi verificare usando il sta giocando proprietà, chiamatela pausa() metodo e visualizza l'icona "play" nel menu ImageButton. Altrimenti, chiama il inizio() metodo e visualizzare l'icona "pausa".

val songPlaying: Boolean? = mediaPlayer? .isPlaying if (songPlaying == true) mediaPlayer? .pause () playButton? .imageResource = R.drawable.ic_play_arrow_black_24dp else mediaPlayer? .start () playButton? .imageResource = R.drawable.ic_pause_black_24dp

Il nostro componente Anko è ora pronto.

9. Visualizzazione del componente Anko

La semplice creazione di un componente Anko non è sufficiente. Devi anche assicurarti di renderizzarlo chiamando il suo setContentView () metodo e passando un'attività ad esso. Per ora, puoi passare l'attività principale ad esso.

Se lo desideri, se vuoi che l'app inizi a riprodurre un brano non appena l'utente lo apre, puoi chiamare il visualizzarloRandom () metodo di nuovo ora.

playerUI.setContentView (this @ MainActivity) playerUI.playRandom ()

La nostra app è pronta. Se lo esegui su un dispositivo che ha uno o più file MP3 con tag ID3 formattati correttamente e copertine di album incorporati, dovresti vedere qualcosa di simile a questo:

Conclusione

In questo tutorial, hai imparato come creare un'app di lettore musicale con una complessa gerarchia di viste usando solo Anko e Kotlin. Mentre lo facevi, hai lavorato con diverse funzionalità avanzate di entrambi, come le coroutine e gli helper dei parametri di layout. Hai anche imparato come rendere il codice Anko più modulare e riutilizzabile creando componenti Anko.

Sentiti libero di aggiungere più funzionalità all'app o modificarne l'aspetto per dargli un tocco personale!

E mentre sei qui, dai uno sguardo ai nostri altri post su Kotlin e alla codifica delle app per Android!