I'm trying to make an app to play music files from the internal storage of the phone.
This is the first method where all the songs are listed in a ListView.
public void fileSearch() {
String[] loadSongs = {MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DISPLAY_NAME};
Cursor audioCursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, loadSongs, null, null, null);
if (audioCursor != null) {
if (audioCursor.moveToFirst()) {
do {
int audioIndex = audioCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME);
audioList.add(audioCursor.getString(audioIndex));
} while (audioCursor.moveToNext());
}
}
audioCursor.close();
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, android.R.id.text1, audioList);
listSongs.setAdapter(adapter);
listSongs.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectedSong(position);
}
});
}
And this method should be playing the song selected by the user in the previous list.
public void selectedSong(int position) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, android.R.id.text1, audioList);
Toast.makeText(MainActivity.this, "You have selected the song:" + adapter.getItem(position), Toast.LENGTH_SHORT).show();
File songSelectedPath = getFileStreamPath(adapter.getItem(position));
Uri uri = Uri.fromFile(songSelectedPath);
Log.d("Adapter", "AdapterToStringPath: " + uri);
Log.d("Pointer", "Pointer: " + position);
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer = MediaPlayer.create(this,uri);
mediaPlayer.start();
}
The error comes from this line mediaPlayer = MediaPlayer.create(this,uri);
Attempt to invoke virtual method 'void android.media.MediaPlayer.start()' on a null object reference
The problem is you are adding an invalid path to the MediaPlayer. To get the correct path you can use Cursor to find the name of your selected songs and get its path. in short I have to modify the signature of your method in order to send the name of the file directly without passing again by the adapter this is the method :
public void selectedSong(String songName) {
String[] loadSongs = {MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME};
String selection1 = MediaStore.Audio.Media.DISPLAY_NAME + " = ?";
String[] selectionArgs = new String[]{songName};
Cursor audioCursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, loadSongs, selection1, selectionArgs, null);
if (audioCursor != null) {
if (audioCursor.moveToFirst()) {
int audioIndex = audioCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
String path = audioCursor.getString(audioIndex);
Log.e("TAG", "selectedSong: " + path);
Uri uri = Uri.fromFile(new File(path));
Log.d("Adapter", "AdapterToStringPath: " + uri);
MediaPlayer mediaPlayer = new MediaPlayer();
Log.e("TAG", "selectedSong: " + uri);
mediaPlayer = MediaPlayer.create(this, uri);
mediaPlayer.start();
}
}
and on your listener call it like below :
listSongs.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectedSong(audioList.get(position));
}
});
The method that I have mounted above may not work correctly let's imagine we have a file of the same Name
on different Folders
in this case it is quite possible that you are mistaken on a file because we will get the file path
from its name
.
So I suggest you create an Object
which contains the Filename
and the Path
and add it to the list of songs
, to display an item you need the Dispalyed_Name
and when you click on a song you get the Path
I think it's easier to do. do not hesitate to leave a comment if you did not understand what I suggested