1

MediaPlayer を使用してサウンドを再生する IntentService を開始する BroadcastReceiver をトリガーする繰り返しアラームがあります。ただし、サウンドが終了する前に IntentService からのスレッドが終了し、ログに警告メッセージが表示されるため、OnCompletionListener (リソースの解放に使用) は呼び出されません。

Handler{4072a788} sending message to a Handler on a dead thread

oncompletionlistener が呼び出されるまでスレッドを存続させるにはどうすればよいですか。または、私が望むものを達成するためのより良いアプローチはありますか?

4

2 に答える 2

0

ローカル サービス経由で再生されるコントロール メディア プレーヤーの場合、CarefulMediaPlayer(mp, this); のように、メディア プレーヤーの参照を他のクラスに送信することをお勧めします。このクラスでは、メディア プレーヤーのすべてのプロパティを処理します。お役に立てると思います。

ありがとう

于 2012-12-14T08:55:44.380 に答える
0

私はこの問題にしばらく苦労しましたが、最終的に以下のクラスを使用して適切に動作するようになりました。アイデアは、生き続けてすべての MediaPlayer ロジックを処理する Looper でスレッドを使用することです。

サービスが明示的な停止メッセージを受信した場合にのみ、ルーパーを終了してスレッドをクリーンアップします

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");       
}

}
于 2012-12-27T22:01:11.073 に答える