Skip to content Skip to sidebar Skip to footer

Ensure Mediaplayer Oncompletionlistener Is Called And The Thread Is Not Dead

I have a recurrent alarm that triggers a BroadcastReceiver that starts an IntentService that plays a sound using MediaPlayer. However, my OnCompletionListener (used for realeasing

Solution 1:

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

Solution 2:

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

publicclassPlayServiceextendsIntentService {
privatestatic PowerManager.WakeLock wakeLock;
privatestaticfinalStringTAG="PlayService";
privatestaticStringLOCK_NAME= TAG;
publicstaticfinalStringEXTRA_FILE="file";
publicstaticfinalStringACTION_PLAY="play";
privatestaticfinalStringACTION_STOP="stop";
publicstaticfinalintMSG_START=1;
publicstaticfinalintMSG_STOP=2;

publicPlayService(String name) {
    super(name);
}

publicPlayService() {
    super("PlayService");
}

@OverridepublicvoidonCreate() {
    super.onCreate();
}

@OverrideprotectedvoidonHandleIntent(Intent intent) {
    Messagemsg=newMessage();
    if (ACTION_PLAY.equalsIgnoreCase(intent.getAction())) {
        StringfileName= intent.getExtras().getString(EXTRA_FILE);
        msg.what = MSG_START;
        msg.obj = fileName;
    } elseif (ACTION_STOP.equalsIgnoreCase(intent.getAction())) {
        msg.what = MSG_STOP;
    }
    try {
        PlayMediaThread.getInstance(this).sendMessage(msg);
    } catch (InterruptedException e) {
        Log.e(TAG, e.getMessage());
    }
}

publicstatic PowerManager.WakeLock acquireLock(Context context) {
    if (wakeLock == null || !wakeLock.isHeld()) {
        PowerManagerpowerManager= (PowerManager) context
                .getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                LOCK_NAME);
        wakeLock.setReferenceCounted(true);
        wakeLock.acquire();
    }
    return wakeLock;
}

publicstaticvoidreleaseLock(Context context) {
    if (wakeLock != null && wakeLock.isHeld()) {
        wakeLock.release();
    }
}

 }

classPlayMediaThreadextendsThreadimplementsOnCompletionListener,
    OnErrorListener, OnPreparedListener {
privatestaticSemaphoresemaphore=newSemaphore(0);
privatestatic Handler handler;
privatestatic Looper myLooper;
privatestatic Context context;
privatestatic String currentFileName;
privatestatic MediaPlayer player;
privatestatic PlayMediaThread instance;
privatestaticfinalStringTAG="PlayMediaThread";

privatePlayMediaThread(Context context)throws InterruptedException {
    super(TAG);
    PlayMediaThread.context = context;
    start();
    // To insure that the looper was initialized correctly before return an// instance
    semaphore.acquire();
}

publicstatic PlayMediaThread getInstance(Context context)throws InterruptedException {
    if (instance == null) {
        instance = newPlayMediaThread(context);
    }
    PlayMediaThread.context = context;
    return instance;
}

publicvoidsendMessage(Message msg) {
    handler.sendMessage(msg);
}

publicvoidquitLooper() {
    try {
        if (myLooper != null) {
            myLooper.quit();
            Log.i(TAG, "After quit");

        }
    } catch (Exception ex) {
        Log.e(TAG, ex.getMessage());
    }
}

@Overridepublicvoidrun() {
    Looper.prepare();
    myLooper = Looper.myLooper();
    handler = newHandler() {
        @OverridepublicvoidhandleMessage(Message msg) {
            if (msg.what == PlayService.MSG_START) {
                startPlayer((String) msg.obj);
            } elseif (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();      
}

privatevoidstopPlayer(boolean clean) {                
    if (player != null) {
        if (player.isPlaying()) {
            player.stop();
        }
        player.release();
        player = null;
    }
    if (clean) {
                    PlayService.releaseLock(context);
        quitLooper();
        instance = null;

    }
}

privatevoidstartPlayer(String fileName) {
    if (player != null && player.isPlaying() && currentFileName != null
            && currentFileName.equalsIgnoreCase(fileName)) {
        return;
    }
    currentFileName = fileName;
    stopPlayer(false);

    player = newMediaPlayer();
    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());
    }
}

@OverridepublicbooleanonError(MediaPlayer mp, int arg1, int arg2) {
    Log.e(TAG, "onError");      

    stopPlayer(true);

    returnfalse;
}

@OverridepublicvoidonCompletion(MediaPlayer mp) {
    Log.d(TAG, "onCompletion");
            // Just to quit the looper and clean the thread
            stopPlayer(true);
}

@OverridepublicvoidonPrepared(MediaPlayer mp) {
    Log.d(TAG, "onPrepared");       
}

}

Post a Comment for "Ensure Mediaplayer Oncompletionlistener Is Called And The Thread Is Not Dead"