MainActivity
public class MainActivity extends AppCompatActivity {
private final String TAG = this.getClass().getName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
//ToolBar
mToolbar = findViewById(R.id.mToolbar);
setSupportActionBar(mToolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(R.string.library);
}
//Method call permission
checkUserPermission();
scanSongs(false);
}
/**
* Starts the background process of scanning the songs.
*
* @param forceScan If we should scan again. You should set
* this to true if you want to scan again
* the database.
* Otherwise, leave it `false` so we don't
* rescan the songs when this Activity
* is created again for some reason.
*/
void scanSongs(boolean forceScan) {
// Loading all the songs from the device on a different thread.
// We'll only actually do it if they weren't loaded already
//
// See the implementation right at the end of this class.
if ((forceScan) || (! Main.songs.isInitialized())) {
Toast.makeText(MainActivity.this,
"Scanning songs on the device",
Toast.LENGTH_LONG);
new ScanSongs().execute();
}
}
@Override
protected void onStart() {
super.onStart();
//Main.startMusicService(this);
}
public class ScanSongs extends AsyncTask<String, Integer, String> {
/**
* The action we'll do in the background.
*/
@Override
protected String doInBackground(String... params) {
try {
// Will scan all songs on the device
Main.songs.getSongs(MainActivity.this, "external");
return "Finished scanning songs";
}
catch (Exception e) {
Log.e("Couldn't execute task", e.toString());
return "Error occurred when scanning songs";
}
}
/**
* Called once the background processing is done.
*/
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Toast.makeText(MainActivity.this,
result,
Toast.LENGTH_LONG).show();
}
}
SongList Class
This is the class where i fetch all the songs from the device.
public class SongList {
private final String TAG = this.getClass().getName();
public ArrayList<QuerySongs> songList = new ArrayList<QuerySongs>();
/**
* Flag that tells if successfully scanned all songs.
*/
private boolean scannedSongs;
/**
* Flag that tells if we're scanning songs right now.
*/
private boolean scanningSongs;
/**
* Tells if we've successfully scanned all songs on
* the device.
*
* This will return `false` both while we're scanning
* for songs and if some error happened while scanning.
*/
public boolean isInitialized() {
return scannedSongs;
}
/**
* Tells if we're currently scanning songs on the device.
*/
public boolean isScanning() {
return scanningSongs;
}
public void getSongs(Context context, String location){
Uri songUri = ((location == "external")?
MediaStore.Audio.Media.INTERNAL_CONTENT_URI:
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
Uri genresUri = ((location == "external")?
MediaStore.Audio.Genres.INTERNAL_CONTENT_URI:
MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI);
Uri playListUri = ((location == "external")?
MediaStore.Audio.Playlists.INTERNAL_CONTENT_URI:
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI);
// Checking for flags so we don't get called twice
if (scanningSongs)
return;
scanningSongs = true;
//Query devices for files (This class provides applications access to the content model.)
ContentResolver contentResolver = context.getContentResolver();
//This interface provides random read-write access to the result set returned by a database query.
Cursor myCursor;
//This is the information i want to get from all the songs on my device.
//Columns for audio file that show up in multiple tables.
String SONG_ID = MediaStore.Audio.Media._ID;
String SONG_DATA = MediaStore.Audio.Media.DATA;
String SONG_ALBUM = MediaStore.Audio.Media.ALBUM;
String SONG_TITLE = MediaStore.Audio.Media.TITLE;
String SONG_ARTIST = MediaStore.Audio.Media.ARTIST;
//This is what i'll retrieve from the song table.
String[] songColumns = {
SONG_ID,
SONG_DATA,
SONG_ALBUM,
SONG_TITLE,
SONG_ARTIST,
};
//Show music files only (IS_MUSIC returns Non-zero if the audio file is music).
final String musicOnly = MediaStore.Audio.Media.IS_MUSIC+"=1";
myCursor = contentResolver.query(songUri, songColumns, musicOnly, null, null);
if (myCursor != null && myCursor.moveToFirst()) {
int songId = myCursor.getInt(myCursor.getColumnIndexOrThrow(SONG_ID));
String songData = myCursor.getString(myCursor.getColumnIndexOrThrow(SONG_DATA));
String songTitle = myCursor.getString(myCursor.getColumnIndexOrThrow(SONG_TITLE));
String songArtist = myCursor.getString(myCursor.getColumnIndexOrThrow(SONG_ARTIST));
String songAlbum = myCursor.getString(myCursor.getColumnIndexOrThrow(SONG_ALBUM));
do {
QuerySongs querySongs = new QuerySongs(songId, songData);
querySongs.setTitle(songTitle);
querySongs.setArtist(songArtist);
querySongs.setAlbum(songAlbum);
//Add the song to the global ArrayList 'songList'.
songList.add(querySongs);
} while (myCursor.moveToNext());
}else{
//What to do if no songs are found?
Log.e(TAG, "No songs found on the device!");
}
myCursor.close();
scannedSongs = true;
scanningSongs = false;
}
public void destroy() {
songList.clear();
}
/**
*
* @return Alphabetically sorted list with all the artists from the songs on the device.
*/
public ArrayList<String> getArtist(){
ArrayList<String> artists = new ArrayList<String >();
for (QuerySongs querySongs: songList){
String artist = querySongs.getArtist();
if (artist!=null && !artist.contains(artist)){
artists.add(artist);
}
}
//Using Collection.sort static operation we can sort ArrayList elements in ascending order.
Collections.sort(artists);
return artists;
}
Main Class which contains all the basic logic from my app
public class Main {
/**
* All the songs on the device.
*/
public static SongList songs = new SongList();
/**
* Contains the songs that are going to be shown to
* the user on a particular menu.
*
* @note IGNORE THIS - don't mess with it.
*
* Every `ActivityMenu*` uses this temporary variable to
* store subsections of `SongList` and set `ActivityListSongs`
* to display it.
*/
public static ArrayList<QuerySongs> songList = null;
/**
* The MediaPlayerService which plays our songs.
*/
public static MediaPlayerService mediaPlayerService = null;
/**
* Flag that checks if our service is bound or not.
*/
public static Boolean serviceBound;
/**
* TAG to get the class name ( helps for logging;
* Log.v(); // Verbose
* Log.d(); // Debug
* Log.i(); // Info
* Log.w(); // Warning
* Log.e(); // Error
* )
*/
private final String TAG = this.getClass().getName();
/**
* The connection to the MediaPlayerService.
* We've bound to Service, cast the IBinder and get Service instance
* onServiceConnected --> Service is bound. (TRUE)
* onServiceDisconnected --> Service is unbound. (FALSE)
*/
public static ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MediaPlayerService.LocalBinder binder = (MediaPlayerService.LocalBinder) service;
mediaPlayerService = binder.getService();
mediaPlayerService.setList(Main.songs.songList);
serviceBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
serviceBound = false;
}
};
private static Intent serviceIntent = null;
public static void startMusicService(Context context){
if (serviceIntent == null && mediaPlayerService == null){
serviceIntent = new Intent(context, MediaPlayerService.class);
context.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
context.startService(serviceIntent);
}else{
}
}
public static void stopMusicService(Context context){
if (serviceIntent != null){
context.stopService(serviceIntent);
serviceIntent = null;
mediaPlayerService = null;
}
}
public static void destroy(){
songs.destroy();
}
}
Summary problem
So when i start the app it shows a toast an error occurred when scanning for songs in the background. I scan for the songs in my MainActivity (Class ScanSongs). So the problem is a nullpointerexception, but i dont know why it causes an nullpointer? This means there is a problem in my SongList Class getSongs. I've been working hours to find my problem but still didn't find it.
Can someone help me?
LOGCAT; 06-11 00:24:30.793 3158-3366/com.vince_mp3player.mp3player E/Couldn't execute task: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference 06-11 00:24:30.793 3158-3366/com.vince_mp3player.mp3player W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference 06-11 00:24:30.799 3158-3366/com.vince_mp3player.mp3player W/System.err: at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:915) at com.vince_mp3player.mp3player.SongList.getSongs(SongList.java:149) at com.vince_mp3player.mp3player.activities.MainActivity$ScanSongs.doInBackground(MainActivity.java:146) at com.vince_mp3player.mp3player.activities.MainActivity$ScanSongs.doInBackground(MainActivity.java:136) at android.os.AsyncTask$2.call(AsyncTask.java:304) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at java.lang.Thread.run(Thread.java:761)
Thanks in advance,
Vince