Reputation: 165
I have been going round in circles on this one for days. I am following a tutorial to create a music player service: part 2 of music player tutorial
I think I've followed it correctly, but I get an error when it tries to set the song ID because the service has not been started correctly. Checking back it never calls the onBind method of the MusicService class. Normally this is caused by not having the service set correctly in the android manifest. However, I have looked at many help pages, changed my service call accordingly, and I don't think it's the source of the error. Any ideas what I am doing wrong?
Android manifest:
<uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTop"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<service android:name="mycompany.mediaplayer.MusicService">
</service>
</manifest>
MainActivity.java
package mycompany.mediaplayer;
import android.provider.BaseColumns;
import android.provider.UserDictionary;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.os.IBinder;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.MenuItem;
import android.view.View;
import mycompany.mediaplayer.MusicService.MusicBinder;
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;
public class MainActivity extends ActionBarActivity {
private ArrayList<Song> songList;
private ListView songView;
private MusicService musicSrv;
private Intent playIntent;
private boolean musicBound=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
songView = (ListView)findViewById(R.id.song_list);
songList = new ArrayList<Song>();
getSongList();
Collections.sort(songList, new Comparator<Song>(){
public int compare(Song a, Song b){
return a.getTitle().compareTo(b.getTitle());
}
});
SongAdapter songAdt = new SongAdapter(this, songList);
songView.setAdapter(songAdt);
}
//connect to the service
private ServiceConnection musicConnection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicBinder binder = (MusicBinder)service;
//get service
musicSrv = binder.getService();
//pass list
musicSrv.setList(songList);
musicBound = true;
Log.i("onServiceConnected", "Have called connection");
Log.i("onServiceConnected", String.valueOf(musicSrv));
}
@Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
}
};
@Override
protected void onStart() {
super.onStart();
if(playIntent==null){
Log.i("onStart", "Binding service");
playIntent = new Intent(this, MusicService.class);
Log.i("onStart", "Play intent "+String.valueOf(playIntent));
Log.i("onStart", String.valueOf(bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE)));
startService(playIntent);
}
Log.i("onStart", "Have started the activity");
Log.i("onStart", String.valueOf(musicSrv));
}
@Override
protected void onDestroy() {
stopService(playIntent);
musicSrv=null;
super.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
// //noinspection SimplifiableIfStatement
// if (id == R.id.action_settings) {
// return true;
// }
switch (item.getItemId()) {
case R.id.action_shuffle:
//shuffle
break;
case R.id.action_end:
stopService(playIntent);
musicSrv=null;
System.exit(0);
break;
}
return super.onOptionsItemSelected(item);
}
public void songPicked(View view){
Log.i("songPicked", String.valueOf(musicSrv));
Log.i("songPicked", String.valueOf(Integer.parseInt(view.getTag().toString())));
int song_number = Integer.parseInt(view.getTag().toString());
Log.i("songPicked", String.valueOf(song_number));
musicSrv.setSong(song_number);
musicSrv.playSong();
}
public void getSongList() {
//retrieve song info
ContentResolver musicResolver = getContentResolver();
Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);
Log.i("MusicRetriever", "Query finished. " + (musicCursor == null ? "Returned NULL." : "Returned a cursor."));
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));
//Log.i("MusicRetriever", "Added song" + thisTitle);
}
while (musicCursor.moveToNext());
}
}
}
MusicService.java
package mycompany.mediaplayer;
/**
* Created by Neill on 28/02/2016.
*/
import java.util.ArrayList;
import android.app.Service;
import android.content.ContentUris;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
public class MusicService extends Service implements
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener {
//media player
private MediaPlayer player;
//song list
private ArrayList<Song> songs;
//current position
private int songPosn;
private final IBinder musicBind = new MusicBinder();
public void onCreate(){
//create the service
super.onCreate();
//initialize position
songPosn=0;
//create player
Log.i("onCreate", "Creating service");
player = new MediaPlayer();
initMusicPlayer();
}
public void onCompletion(MediaPlayer mp) {
}
public boolean onError(MediaPlayer mp, int a, int b) {
return false;
}
public void initMusicPlayer(){
//set player properties
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
}
public void setList(ArrayList<Song> theSongs){
songs=theSongs;
}
public class MusicBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
Log.i("onBind", "Returning bind");
return musicBind;
}
@Override
public boolean onUnbind(Intent intent){
player.stop();
player.release();
return false;
}
public void playSong(){
//play a song
player.reset();
//get song
Song playSong = songs.get(songPosn);
//get id
long currSong = playSong.getID();
//set uri
Uri trackUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
currSong);
try{
player.setDataSource(getApplicationContext(), trackUri);
}
catch(Exception e){
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.prepareAsync();
}
@Override
public void onPrepared(MediaPlayer mp) {
//start playback
mp.start();
}
public void setSong(int songIndex){
songPosn=songIndex;
}
}
And finally the logcat:
03-17 21:55:43.986 29835-29835/? I/art: Late-enabling -Xcheck:jni
03-17 21:55:44.028 29835-29835/? W/ResourceType: Found multiple library tables, ignoring...
03-17 21:55:44.034 29835-29835/? W/ResourceType: Found multiple library tables, ignoring...
03-17 21:55:44.038 29835-29835/? W/ResourceType: Found multiple library tables, ignoring...
03-17 21:55:44.243 29835-29835/mycompany.mediaplayer I/MusicRetriever: Query finished. Returned a cursor.
03-17 21:55:44.308 29835-29835/mycompany.mediaplayer I/onStart: Binding service
03-17 21:55:44.308 29835-29835/mycompany.mediaplayer I/onStart: Play intent Intent { cmp=mycompany.mediaplayer/.MusicService }
03-17 21:55:44.310 29835-29835/mycompany.mediaplayer I/onStart: false
03-17 21:55:44.310 29835-29835/mycompany.mediaplayer I/onStart: Have started the activity
03-17 21:55:44.310 29835-29835/mycompany.mediaplayer I/onStart: null
03-17 21:55:44.322 29835-29864/mycompany.mediaplayer D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
03-17 21:55:44.337 29835-29835/mycompany.mediaplayer D/Atlas: Validating map...
03-17 21:55:44.399 29835-29864/mycompany.mediaplayer I/Adreno-EGL: <qeglDrvAPI_eglInitialize:410>: EGL 1.4 QUALCOMM build: AU_LINUX_ANDROID_LA.BF.1.1.1_RB1.05.01.00.042.030_msm8226_LA.BF.1.1.1_RB1__release_AU ()
OpenGL ES Shader Compiler Version: E031.25.03.06
Build Date: 06/10/15 Wed
Local Branch:
Remote Branch: quic/LA.BF.1.1.1_rb1.24
Local Patches: NONE
Reconstruct Branch: AU_LINUX_ANDROID_LA.BF.1.1.1_RB1.05.01.00.042.030 + 6151be1 + NOTHING
03-17 21:55:44.401 29835-29864/mycompany.mediaplayer I/OpenGLRenderer: Initialized EGL, version 1.4
03-17 21:55:44.421 29835-29864/mycompany.mediaplayer D/OpenGLRenderer: Enabling debug mode 0
03-17 21:55:44.780 29835-29835/mycompany.mediaplayer I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@285dcbce time:12224185
03-17 21:55:46.802 29835-29835/mycompany.mediaplayer I/songPicked: null
03-17 21:55:46.802 29835-29835/mycompany.mediaplayer I/songPicked: 6
03-17 21:55:46.802 29835-29835/mycompany.mediaplayer I/songPicked: 6
03-17 21:55:46.803 29835-29835/mycompany.mediaplayer D/AndroidRuntime: Shutting down VM
03-17 21:55:46.804 29835-29835/mycompany.mediaplayer E/AndroidRuntime: FATAL EXCEPTION: main
Process: mycompany.mediaplayer, PID: 29835
java.lang.IllegalStateException: Could not execute method of the activity
at android.view.View$1.onClick(View.java:4096)
at android.view.View.performClick(View.java:4856)
at android.view.View$PerformClick.run(View.java:19956)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5371)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:945)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:740)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at android.view.View$1.onClick(View.java:4091)
at android.view.View.performClick(View.java:4856)
at android.view.View$PerformClick.run(View.java:19956)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5371)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:945)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:740)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void mycompany.mediaplayer.MusicService.setSong(int)' on a null object reference
at mycompany.mediaplayer.MainActivity.songPicked(MainActivity.java:130)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at android.view.View$1.onClick(View.java:4091)
at android.view.View.performClick(View.java:4856)
at android.view.View$PerformClick.run(View.java:19956)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5371)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:945)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:740)
03-17 21:55:48.109 29835-29835/mycompany.mediaplayer I/Process: Sending signal. PID: 29835 SIG: 9
Thanks in advance for your help.
Upvotes: 1
Views: 3144
Reputation: 165
Fixed it!
It took a while to track down, but my mistake was putting the call to "service" outside the "application" section in the android manifest. Moving the service line upwards fixes the problem.
Upvotes: 2