Ensure MediaPlayer onCompletionListener is called and the thread is not dead

后端 未结 2 677
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-24 10:00

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

相关标签:
2条回答
  • 2021-01-24 11:05

    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

    0 讨论(0)
  • 2021-01-24 11:05

    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");       
    }
    
    }
    
    0 讨论(0)
提交回复
热议问题