Home > News su Android, tutte le novità > Come creare un music player per Android: il setup del progetto

Come creare un music player per Android: il setup del progetto

music player per Android

La piattaforma Android ci fornisce diverse risorse per poter gestire la riproduzione musicale, quindi per creare un’interfaccia tra l’utente e i brani musicali presenti nella memoria del dispositivo. In questa breve serie di guide vedremo come creare un music player per Android, un’applicazione che sia in grado di visualizzare tutti i brani presenti sul dispositivo e riprodurli, dunque avremo naturalmente la necessità di inserire i consueti controlli utente per interagire con la riproduzione musicale in corso. Qui di seguito potete vedere un semplice prototipo di come si mostrerà l’applicazione.

music player per Android

La guida si rivolge a chiunque abbia una conoscenza basilare dello sviluppo Android, dunque è preferibile innanzitutto avere una conoscenza base dell’argomento (potete seguire queste lezioni per iniziare). Quali sono le classi che andremo ad utilizzare per creare il nostro music player per Android? Scopriamole insieme:

  • ContentResolver: ci permetterà di trovare i brani sul device;
  • MediaPlayer: consente di riprodurre i brani musicali;
  • MediaController: essa ci darà la possibilità di gestire la riproduzione musicale a nostro piacimento;
  • Service: un’istanza di Service è necessaria quando vorremo riprodurre brani musicali anche mentre non stiamo interagendo direttamente con l’applicazione.

In questo tutorial, il nostro scopo sarà quello di creare l’applicazione, effettuare quindi il setup del progetto, interrogare il dispositivo per trovare i file audio presenti all’interno e, infine, inserire i brani in un elenco. Nella seconda lezione faremo in modo che, con un semplice click, questi vengano riprodotti (anche mentre interagiamo con altre applicazioni). Nella terza parte, infine, aggiungeremo i controlli utente grazie a MediaController per gestire la riproduzione musicale.

Creare il progetto

Come di consueto, il primo passo consiste nella creazione del progetto Android. Chiunque abbia un minimo di conoscenze nel mondo della programmazione Android saprà già come fare, in alternativa qui trovate tutte le informazioni necessarie per iniziare il lavoro. Ci sono, naturalmente, alcuni fattori da tenere in considerazione.

Innanzitutto, vi consigliamo di utilizzare API di livello 16 (come minimo) affinché non abbiate problemi con le istruzioni che verranno spiegate in questo tutorial. Inoltre, la prima cosa da fare consiste nell’aggiungere un ulteriore permesso nel manifesto Android (file manifest.xml), aggiungendo la seguente linea di codice:

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

Essa consentirà all’applicazione di continuare a riprodurre il file musicale anche quando lo smartphone va in stand-by. Il manifesto Android che verrà creato automaticamente durante il setup del progetto, inoltre, conterrà già delle informazioni basilari sull’activity principale, ma dovrete inserire ulteriori attributi, descritti qui di seguito:

<activity
  android:name="com.example.musicplayer.MainActivity"
  android:label="@string/app_name"
  android:launchMode="singleTop"
  android:screenOrientation="portrait" >

Per semplicità, utilizzeremo portrait per avere un orientamento verticale, mentre l’attributo launchMode ci aiuterà nel tornare all’applicazione quando ci “allontaniamo” da essa. Infatti, verrà mostrata una notifica indicante l’attuale brano in esecuzione e, cliccando su di esso, verremo automaticamente riportati all’app. In questo modo, inoltre, stiamo già andando ad utilizzare la classe Service per la riproduzione musicale, dunque dovremo inserire nel nostro manifesto Android, dopo l’elemento activity, anche un elemento service, descritto qui di seguito:

<service android:name="com.example.musicplayer.MusicService" />

Naturalmente, potete cambiare a vostro piacimento il nome del package e delle classi utilizzate. Successivamente, potete andare a modificare il layout del vostro progetto, modificando il contenuto generato automaticamente con quello seguente:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical"
  android:background="#FF330000"
  tools:context=".MainActivity" >
 
  <ListView
    android:id="@+id/song_list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >
  </ListView>
 
</LinearLayout>

Assicuratevi, naturalmente, che l’attributo di tools:context coincida con il nome dell’activity che avete scelto. Notate che abbiamo inserito nel layout anche l’elemento ListView, il quale presenterà la lista dei brani. Vogliamo, inoltre, includere due voci di menù per uscire dall’applicazione e per attivare/disattivare la funzione shuffle. Aprite, quindi, il file relativo al vostro menù (res/menu/main.xml) e rimpiazzate il contenuto con il seguente:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
 
  <item
    android:id="@+id/action_shuffle"
    android:icon="@drawable/rand"
    android:orderInCategory="1"
    android:showAsAction="always"
    android:title="Shuffle"/>
 
  <item
    android:id="@+id/action_end"
    android:icon="@drawable/end"
    android:orderInCategory="2"
    android:showAsAction="always"
    android:title="End"/>
 
</menu>

Se preferite, le stringhe presenti in title potete memorizzarle nel file res/values/strings.xml. Ad ogni modo, i due elementi inseriti si riferiscono a file disegnabili, quindi abbiamo la necessità di creare e inserite alcune immagini nelle nostre risorse. Di seguito trovare tre immagini, alle quali ci riferiremo con i nomi rand, end e play (potete constatarlo voi stessi dal modo in cui sono state rinoninate le immagini), dunque assicuratevi che i nomi coincidano.

android_music_player_rand

android_music_player_play

android_music_player_end

Naturalmente, dovrete copiare le immagini nella cartella drawable del vostro progetto.

Interrogare il device per trovare i brani

A questo punto, è giunto il momento di cercare i brani all’interno del vostro device. Prima di tutto, creiamo una classe Song.java, la utilizzeremo come modello di riferimento per ogni singolo brano, dunque utilizzeremo un costruttore che, una volta istanziato, inizializzerà gli attributi per ogni brano. Inizialmente utilizzeremo un ID per ogni brano, il nome di quest’ultimo e, naturalmente, il relativo artista.

Inoltre, creeremo i classici metodi getters che serviranno a restituirci gli attributi appena visti. Ecco come si presenterà la classe Song.java:

private long id;
private String title;
private String artist;

public Song(long songID, String songTitle, String songArtist) {
  id=songID;
  title=songTitle;
  artist=songArtist;
}

public long getID() {
  return id;
}

public String getTitle() {
  return title;
}

public String getArtist() {
  return artist;
}

Ora possiamo passare, finalmente, a modificare la nostra MainActivity.java. Prima di modificare il metodo onCreate, vediamo quali sono le classi da importare e le variabili da dichiarare.

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import android.net.Uri;
import android.content.ContentResolver;
import android.database.Cursor;
import android.widget.ListView;

private ArrayList<Song> songList;
private ListView songView;

Poiché vogliamo memorizzare i brani in una lista, utilizzeremo l’oggetto ListView per visualizzarli. In onCreate, invece, istanziamo songList e recuperiamo l’istanza di ListView con l’ID dichiarato precedentemente layout principale.

songView = (ListView)findViewById(R.id.song_list);
songList = new ArrayList<Song>();
getSongList();

Come potete vedere, abbiamo chiamato anche getSongList() che ci aiuterà a recuperare le informazioni sui brani. Andiamo, dunque, a creare questo metodo dopo onCreate, istanziando innanzitutto i 3 oggetti principali: ContentResolver, Uri e Cursor. Quest’ultimo consente di effettuare la query al dispositivo utilizzando l’oggetto ContentResolver per ricercare l’URI dei file musicali. Successivamente iteriamo i risultati controllando innanzitutto che i dati siano validi e, successivamente, recuperiamo gli indici di colonna e gli utilizziamo per creare un nuovo oggetto Song che verrà aggiungo a songList.

public void getSongList() {
 ContentResolver musicResolver = getContentResolver();
 Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
 Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);

 if(musicCursor!=null && musicCursor.moveToFirst()){
   //get columns
   int titleColumn = musicCursor.getColumnIndex
     (android.provider.MediaStore.Audio.Media.TITLE);
   int idColumn = musicCursor.getColumnIndex
     (android.provider.MediaStore.Audio.Media._ID);
   int artistColumn = musicCursor.getColumnIndex
     (android.provider.MediaStore.Audio.Media.ARTIST);
   //add songs to list
   do {
     long thisId = musicCursor.getLong(idColumn);
     String thisTitle = musicCursor.getString(titleColumn);
     String thisArtist = musicCursor.getString(artistColumn);
     songList.add(new Song(thisId, thisTitle, thisArtist));
   }
   while (musicCursor.moveToNext());
 }
}

Visualizzare i brani

Arriva il momento di visualizzare i brani. Il primo passo consiste nell’ordinamento, nel nostro esempio ordineremo i brani in base al titolo, quindi sempre in onCreate(), dopo aver chiamato getSongList(), aggiungiamo il seguente codice.

Collections.sort(songList, new Comparator<Song>(){
  public int compare(Song a, Song b){
    return a.getTitle().compareTo(b.getTitle());
  }
});

Ora definiamo il layout per rappresentare ogni singola canzone nella lista, lo chiameremo song.xml e andremo ad aggiungerlo nella directory res/layout.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:onClick="songPicked"
  android:orientation="vertical"
  android:padding="5dp" >
 
  <TextView
    android:id="@+id/song_title"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textColor="#FFFFFF99"
    android:textSize="20sp"
    android:textStyle="bold" />
 
  <TextView
    android:id="@+id/song_artist"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textColor="#FFFFFF99"
    android:textSize="18sp" />
 
</LinearLayout>

Potete modificare il layout come preferite. Ogni canzone della lista sarà rappresentata dal titolo e dal nome dell’artista, quindi utilizziamo le TextView per rappresentare tali dati. Inoltre, notate che abbiamo utilizzato l’attributo onClick, utile per rispondere ai tocchi degli utenti sui brani presenti nell’elenco.

A questo punto abbiamo la necessità di mappare le canzoni nella visualizzazione ad elenco, utilizzeremo quello che viene chiamato Adapter, quindi creiamo una nuova classe che chiamiamo SongAdapter e la estenderemo da BaseAdapter. Ecco come si presenterà inizialmente:

public class SongAdapter extends BaseAdapter {
 
  @Override
  public int getCount() {
    // TODO Auto-generated method stub
    return 0;
  }
 
  @Override
  public Object getItem(int arg0) {
    // TODO Auto-generated method stub
    return null;
  }
 
  @Override
  public long getItemId(int arg0) {
    // TODO Auto-generated method stub
    return 0;
  }
 
  @Override
  public View getView(int arg0, View arg1, ViewGroup arg2) {
    // TODO Auto-generated method stub
    return null;
  }
 
}

Vediamo quali sono le classi che dovremo importare e cosa dichiarare all’interno di SongAdapter.

import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;

private ArrayList<Song> songs;
private LayoutInflater songInf;

Ricordiamo, onde evitare problemi, che la guida è dedicata a coloro che hanno una conoscenza basilare del mondo Java e Android, i quali sapranno senz’altro che le istruzioni riportate sopra non si presentano esattamente nella stessa sequenzialità.

Utilizzeremo LayoutInflater per mappare le stringhe relative al titolo del brano e al nome dell’artista nel layout che abbiamo creato. Dopo le variabili di istanza, come sempre, avremo il costruttore che andremo a creare come riportato qui di seguito:

public SongAdapter(Context c, ArrayList<Song> theSongs){
  songs=theSongs;
  songInf=LayoutInflater.from(c);
}

Infine, passiamo ai metodi generati automaticamente e visti in precedenza. Possiamo lasciare inalterati getItem e getItemId, ma andiamo a modificare getCount e getView come segue.

@Override
public int getCount() {
  return songs.size();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
  //map to song layout
  LinearLayout songLay = (LinearLayout)songInf.inflate
      (R.layout.song, parent, false);
  //get title and artist views
  TextView songView = (TextView)songLay.findViewById(R.id.song_title);
  TextView artistView = (TextView)songLay.findViewById(R.id.song_artist);
  //get song using position
  Song currSong = songs.get(position);
  //get title and artist strings
  songView.setText(currSong.getTitle());
  artistView.setText(currSong.getArtist());
  //set position as tag
  songLay.setTag(position);
  return songLay;
}

Abbiamo modificato getCount affinché ci restituisca la dimensione della lista, mentre per quanto riguarda getView abbiamo impostato il titolo brano e il nome artista recuperando la corretta istanza di Song dall’elenco utilizzando l’ID. Notate soprattutto come avviene la mappatura delle stringhe nelle TextView che abbiamo aggiunto. Inoltre, abbiamo settato e utilizzato un tag che indica la posizione del brano corrente, il quale ci permetterà di riprodurre il brano corretto quando l’utente clicca su un elemento dell’elenco. Ricordate, infatti, che il file di layout song.xml include un attributo onClick. Successivamente, utilizzeremo il metodo proprio per recuperare il tag nella Activity.

A questo punto, ci basterà creare un’istanza di SongAdapter impostandola sulla ListView. Il tutto sempre in onCreate dopo l’ordinamento inserito in precedenza.

SongAdapter songAdt = new SongAdapter(this, songList);
songView.setAdapter(songAdt);

A questo punto, potete avviare l’applicazione e vedere i risultati, tuttavia se cliccate su un brano scatterà un’eccezione perché non abbiamo implementato ancora onClick, operazione che effettueremo nel prossimo tutorial assieme all’implementazione della classe Service che ci servirà per consentire all’utente di interagire con le altre applicazioni durante la riproduzione di un brano.