I have a recurrent alarm that triggers a BroadcastReceiver that starts an IntentService that plays a sound using MediaPlayer. However, my OnCompletionListener (used for realeasi
For Controll Media player that are play via local service, it is better to send Media player reference to other class Like CarefulMediaPlayer(mp, this);. You handle all media player properties in this class. I think it help you.
Thanks
I struggled for sometime with this issue and finally I got it to work properly using the below class. The idea is to use a thread with a Looper that remains alive and handles all the MediaPlayer logic.
I only quit the looper and clean the thread if the service received explicit stop message
public class PlayService extends IntentService {
private static PowerManager.WakeLock wakeLock;
private static final String TAG = "PlayService";
private static String LOCK_NAME = TAG;
public static final String EXTRA_FILE = "file";
public static final String ACTION_PLAY = "play";
private static final String ACTION_STOP = "stop";
public static final int MSG_START = 1;
public static final int MSG_STOP = 2;
public PlayService(String name) {
super(name);
}
public PlayService() {
super("PlayService");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected void onHandleIntent(Intent intent) {
Message msg = new Message();
if (ACTION_PLAY.equalsIgnoreCase(intent.getAction())) {
String fileName = intent.getExtras().getString(EXTRA_FILE);
msg.what = MSG_START;
msg.obj = fileName;
} else if (ACTION_STOP.equalsIgnoreCase(intent.getAction())) {
msg.what = MSG_STOP;
}
try {
PlayMediaThread.getInstance(this).sendMessage(msg);
} catch (InterruptedException e) {
Log.e(TAG, e.getMessage());
}
}
public static PowerManager.WakeLock acquireLock(Context context) {
if (wakeLock == null || !wakeLock.isHeld()) {
PowerManager powerManager = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
LOCK_NAME);
wakeLock.setReferenceCounted(true);
wakeLock.acquire();
}
return wakeLock;
}
public static void releaseLock(Context context) {
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
}
}
}
class PlayMediaThread extends Thread implements OnCompletionListener,
OnErrorListener, OnPreparedListener {
private static Semaphore semaphore = new Semaphore(0);
private static Handler handler;
private static Looper myLooper;
private static Context context;
private static String currentFileName;
private static MediaPlayer player;
private static PlayMediaThread instance;
private static final String TAG = "PlayMediaThread";
private PlayMediaThread(Context context) throws InterruptedException {
super(TAG);
PlayMediaThread.context = context;
start();
// To insure that the looper was initialized correctly before return an
// instance
semaphore.acquire();
}
public static PlayMediaThread getInstance(Context context)
throws InterruptedException {
if (instance == null) {
instance = new PlayMediaThread(context);
}
PlayMediaThread.context = context;
return instance;
}
public void sendMessage(Message msg) {
handler.sendMessage(msg);
}
public void quitLooper() {
try {
if (myLooper != null) {
myLooper.quit();
Log.i(TAG, "After quit");
}
} catch (Exception ex) {
Log.e(TAG, ex.getMessage());
}
}
@Override
public void run() {
Looper.prepare();
myLooper = Looper.myLooper();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == PlayService.MSG_START) {
startPlayer((String) msg.obj);
} else if (msg.what == PlayService.MSG_STOP) {
// when stop command is coming from the activity i.e. user
// explicitly clicked stop, I quit the looper and
// clean the thread
stopPlayer(true);
}
}
};
semaphore.release();
Log.i(TAG, "Before Loop");
Looper.loop();
}
private void stopPlayer(boolean clean) {
if (player != null) {
if (player.isPlaying()) {
player.stop();
}
player.release();
player = null;
}
if (clean) {
PlayService.releaseLock(context);
quitLooper();
instance = null;
}
}
private void startPlayer(String fileName) {
if (player != null && player.isPlaying() && currentFileName != null
&& currentFileName.equalsIgnoreCase(fileName)) {
return;
}
currentFileName = fileName;
stopPlayer(false);
player = new MediaPlayer();
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
player.setOnPreparedListener(this);
try {
player.setDataSource(context, Uri.parse(currentFileName));
player.prepare();
player.start();
PlayService.acquireLock(context);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
@Override
public boolean onError(MediaPlayer mp, int arg1, int arg2) {
Log.e(TAG, "onError");
stopPlayer(true);
return false;
}
@Override
public void onCompletion(MediaPlayer mp) {
Log.d(TAG, "onCompletion");
// Just to quit the looper and clean the thread
stopPlayer(true);
}
@Override
public void onPrepared(MediaPlayer mp) {
Log.d(TAG, "onPrepared");
}
}