New to android, trying to figure out Services. I'm trying to bind a service to an activity, I'm following the examples in the documentation, but I keep getting a NullPointerException on the line marked below(appService.playSong(title)). Checking it in the debugger reveals that appService is indeed null.
public class Song extends Activity implements OnClickListener,Runnable {
protected static int currentPosition;
private ProgressBar progress;
private TextView songTitle;
private MPService appService;
private ServiceConnection onService = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder rawBinder) {
appService = ((MPService.LocalBinder)rawBinder).getService();
}
public void onServiceDisconnected(ComponentName classname) {
appService = null;
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song);
Intent bindIntent = new Intent(Song.this,MPService.class);
bindService(bindIntent,onService,
Context.BIND_AUTO_CREATE);
Bundle b = getIntent().getBundleExtra("songdata");
String title = b.getString("song title");
// ...
appService.playSong(title); // nullpointerexception
// ...
}
Here's the relevant part of the service:
package org.example.music;
// imports
public class MPService extends Service {
private MediaPlayer mp;
public static int currentPosition = 0;
public List<String> songs = new ArrayList<String>();
public static String songTitle;
private static final String MEDIA_PATH = new String("/mnt/sdcard/");
@Override
public void onCreate() {
super.onCreate();
mp = new MediaPlayer();
songs = Music.songs;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
public class LocalBinder extends Binder {
MPService getService() {
return MPService.this;
}
}
private final IBinder binder = new LocalBinder();
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public void playSong(String songPath) {
try {
mp.reset();
mp.setDataSource(songPath);
mp.prepare();
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer arg0) {
nextSong();
}
});
songTitle = songPath.substring(12,songPath.length()-4);
} catch (IOException e) {
Log.v(getString(R.string.app_name),e.getMessage());
}
}
public void nextSong() {
if (++currentPosition >= songs.size()) {
currentPosition = 0;
}
String song = MEDIA_PATH+songs.get(currentPosition);
playSong(song);
}
public void prevSong() {
if (--currentPosition<0) {
currentPosition=songs.size()-1;
}
String song = Music.MEDIA_PATH+songs.get(currentPosition);
playSong(song);
}
public int getSongPosition() {
return mp.getCurrentPosition();
}
public MediaPlayer getMP() {
return mp;
}
}
I have registered the service in AndroidManifest.xml and set android:enabled="true". Do you see any obvious mistakes here?
You are assuming that the bindService() will connect to the service synchronously, but the connection will be available only after onCreate() finshed.
The framework runs onCreate() on the UI thread and bindService() just makes a note to connect to the service later. Connecting to a service will always be done on the UI thread, so this can only happen after onCreate was executed. You can't even count on the connection being set up right after onCreate(). It will happen sometime after that :). Also, the framework might disconnect the service on it's will, though it should only happen in low memory conditions.
So, move the code which works with appService from onCreate() to onServiceConnected() and it's gonna work.
There are two kinds of binds you can make local and remote. Local is only for use by your application and remote if for use by any application that implements certain interface. You should start with local binding.
Local binding tutorial.
Remote binding tutorial.
My solution without bind:
Your service:
good luck.
From a quick glance it looks like you are trying to access your service before the binding has completed. You have to make sure
onServiceConnected
has fired before trying to call any methods on your service.Example:
This example isn't the best but it demonstrates that you have to wait until the binding has completed before trying to access the service.