Android 无法使MediaPlayer.prepareAsync正常工作
我一直在尝试使用prepareAsync()方法和onPrepared()方法实现一个简单的MediaPlayer(音频)。这些是从IntentService中调用的。相关活动仅发送启动和停止意图操作。我已确认活动正在发送事件。 以下是IntentService中的代码:Android 无法使MediaPlayer.prepareAsync正常工作,android,audio,Android,Audio,我一直在尝试使用prepareAsync()方法和onPrepared()方法实现一个简单的MediaPlayer(音频)。这些是从IntentService中调用的。相关活动仅发送启动和停止意图操作。我已确认活动正在发送事件。 以下是IntentService中的代码: package com.javacodegeeks.androidmusic_intentservice; import android.app.IntentService; import android.content.I
package com.javacodegeeks.androidmusic_intentservice;
import android.app.IntentService;
import android.content.Intent;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.widget.Toast;
import java.io.IOException;
import android.net.Uri;
/**
* An {@link IntentService} subclass for handling asynchronous task requests in
* a service on a separate handler thread.
* <p/>
* TODO: Customize class - update intent actions, extra parameters and static
* helper methods.
*/
public class MusicIntentService extends IntentService implements MediaPlayer.OnErrorListener, MediaPlayer.OnPreparedListener {
// TODO: Rename actions, choose action names that describe tasks that this
private static final String ACTION_PLAY = "com.example.action.PLAY";
private static final String ACTION_STOP = "com.example.action.STOP";
static MediaPlayer mMediaPlayer = null;
public MusicIntentService() {
super("MusicIntentService");
}
@Override
public void onHandleIntent(Intent intent) {
if (intent != null) if (intent.getAction().equals(ACTION_PLAY)) {
if (mMediaPlayer == null) {
mMediaPlayer = new MediaPlayer();
String fileName = "android.resource://" + getPackageName() + "/" + R.raw.georgeharrisonlivinginthematerialworld;
try {
mMediaPlayer.setDataSource(this, Uri.parse(fileName));
} catch (IllegalArgumentException e) {
Toast.makeText(getApplicationContext(), "IllegalArgumentException", Toast.LENGTH_LONG).show();
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(), "SecurityException", Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
}
mMediaPlayer.setOnErrorListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnPreparedListener(this);
try {
mMediaPlayer.prepareAsync();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException", Toast.LENGTH_LONG).show();
}
/*calling prepare() and start() works ok*/
/* it is better to have the prepareAsync() and onPrepared() pattern implemented*/
/* try {
mMediaPlayer.prepare();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException prepare()", Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "IOException prepare()", Toast.LENGTH_LONG).show();
}*/
/* try {
mMediaPlayer.start();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException start()", Toast.LENGTH_LONG).show();
}*/
} else if (intent.getAction().equals(ACTION_STOP)) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
}
}
}
/** Called when MediaPlayer is ready */
public void onPrepared(MediaPlayer player) {
try {
mMediaPlayer.start();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException in onPrepared", Toast.LENGTH_LONG).show();
}
}
public boolean onError(MediaPlayer mp, int what, int extra) {
/*
... react appropriately ...
The MediaPlayer has moved to the Error state, must be reset!
*/
return true;
}
}
但是,当我调试并设置以下行的断点时:
mMediaPlayer.setOnErrorListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnPreparedListener(this);
try {
mMediaPlayer.prepareAsync();
并单步执行这些语句,然后在单步执行prepareAsync()语句后选择Resume,代码将到达onPrepared()方法,音频输出正常。
当我取消对prepare()和play()语句的注释并注释掉prepareAsynch()语句时,当我在设置或不设置断点的情况下运行或调试时,会得到音频输出。(这就是为什么我在注释掉的代码中留下来,以显示什么是有效的。)我理解这只是运气,在到达play()方法之前,准备工作已经完成
onError()从未到达过,我知道那里还有工作要做
另一件事是,我确实尝试过:
mMediaPlayer.setOnPreparedListener(MusicIntentService.this);
这似乎没有什么不同。事实上,当我打开一个带有“MusicIntentService.this”的手表窗口时,我看到了与“this”相同的元素和值
如果有人能给我指出正确的方向,我将不胜感激。我的下一步是尝试在调用setOnpreparedListener(..)时实现侦听器,但我想了解为什么当前的实现不能始终如一地工作。
提前谢谢。
吉姆这是我做的
我最初的目标是利用prepareAsync()方法实现一个简单的媒体播放器。这将允许更健壮的设计,因为我们不必只希望媒体播放器在调用start()方法之前达到准备好的状态
如上所述,pskink直截了当地告诉我IntentService不适合处理媒体播放器控件
然后,我假设我将使用一个服务,我开始考虑处理按钮按下,并保持媒体播放器状态与UI一致
根据我对棒棒糖中包含的功能所做的一些阅读,我回到了我从以下网站下载的一个项目:
该活动启动一项服务,处理按钮输入和媒体播放器控制:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent( getApplicationContext(), MediaPlayerService.class );
intent.setAction( MediaPlayerService.ACTION_PLAY );
startService( intent );
}
}
MediaPlayerService如下所示:
/**
* Created by paulruiz on 10/28/14.
*/
public class MediaPlayerService extends Service {
public static final String ACTION_PLAY = "action_play";
public static final String ACTION_PAUSE = "action_pause";
public static final String ACTION_REWIND = "action_rewind";
public static final String ACTION_FAST_FORWARD = "action_fast_foward";
public static final String ACTION_NEXT = "action_next";
public static final String ACTION_PREVIOUS = "action_previous";
public static final String ACTION_STOP = "action_stop";
private MediaPlayer mMediaPlayer;
private MediaSessionManager mManager;
private MediaSession mSession;
private MediaController mController;
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void handleIntent( Intent intent ) {
if( intent == null || intent.getAction() == null )
return;
String action = intent.getAction();
if( action.equalsIgnoreCase( ACTION_PLAY ) ) {
mController.getTransportControls().play();
} else if( action.equalsIgnoreCase( ACTION_PAUSE ) ) {
mController.getTransportControls().pause();
} else if( action.equalsIgnoreCase( ACTION_FAST_FORWARD ) ) {
mController.getTransportControls().fastForward();
} else if( action.equalsIgnoreCase( ACTION_REWIND ) ) {
mController.getTransportControls().rewind();
} else if( action.equalsIgnoreCase( ACTION_PREVIOUS ) ) {
mController.getTransportControls().skipToPrevious();
} else if( action.equalsIgnoreCase( ACTION_NEXT ) ) {
mController.getTransportControls().skipToNext();
} else if( action.equalsIgnoreCase( ACTION_STOP ) ) {
mController.getTransportControls().stop();
}
}
private Notification.Action generateAction( int icon, String title, String intentAction ) {
Intent intent = new Intent( getApplicationContext(), MediaPlayerService.class );
intent.setAction( intentAction );
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, intent, 0);
return new Notification.Action.Builder( icon, title, pendingIntent ).build();
}
private void buildNotification( Notification.Action action ) {
Notification.MediaStyle style = new Notification.MediaStyle();
Intent intent = new Intent( getApplicationContext(), MediaPlayerService.class );
intent.setAction( ACTION_STOP );
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(), 1, intent, 0);
Notification.Builder builder = new Notification.Builder( this )
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle( "Media Title" )
.setContentText( "Media Artist" )
.setDeleteIntent( pendingIntent )
.setStyle(style);
builder.addAction( generateAction( android.R.drawable.ic_media_previous, "Previous", ACTION_PREVIOUS ) );
builder.addAction( generateAction( android.R.drawable.ic_media_rew, "Rewind", ACTION_REWIND ) );
builder.addAction( action );
builder.addAction( generateAction( android.R.drawable.ic_media_ff, "Fast Foward", ACTION_FAST_FORWARD ) );
builder.addAction( generateAction( android.R.drawable.ic_media_next, "Next", ACTION_NEXT ) );
style.setShowActionsInCompactView(0,1,2,3,4);
NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
notificationManager.notify( 1, builder.build() );
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if( mManager == null ) {
initMediaSessions();
}
handleIntent( intent );
return super.onStartCommand(intent, flags, startId);
}
private void initMediaSessions() {
mMediaPlayer = new MediaPlayer();
mSession = new MediaSession(getApplicationContext(), "simple player session");
mController =new MediaController(getApplicationContext(), mSession.getSessionToken());
mSession.setCallback(new MediaSession.Callback(){
@Override
public void onPlay() {
super.onPlay();
Log.e( "MediaPlayerService", "onPlay");
buildNotification( generateAction( android.R.drawable.ic_media_pause, "Pause", ACTION_PAUSE ) );
}
@Override
public void onPause() {
super.onPause();
Log.e( "MediaPlayerService", "onPause");
buildNotification(generateAction(android.R.drawable.ic_media_play, "Play", ACTION_PLAY));
}
@Override
public void onSkipToNext() {
super.onSkipToNext();
Log.e( "MediaPlayerService", "onSkipToNext");
//Change media here
buildNotification( generateAction( android.R.drawable.ic_media_pause, "Pause", ACTION_PAUSE ) );
}
@Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
Log.e( "MediaPlayerService", "onSkipToPrevious");
//Change media here
buildNotification( generateAction( android.R.drawable.ic_media_pause, "Pause", ACTION_PAUSE ) );
}
@Override
public void onFastForward() {
super.onFastForward();
Log.e( "MediaPlayerService", "onFastForward");
//Manipulate current media here
}
@Override
public void onRewind() {
super.onRewind();
Log.e( "MediaPlayerService", "onRewind");
//Manipulate current media here
}
@Override
public void onStop() {
super.onStop();
Log.e( "MediaPlayerService", "onStop");
//Stop media player here
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel( 1 );
Intent intent = new Intent( getApplicationContext(), MediaPlayerService.class );
stopService( intent );
}
@Override
public void onSeekTo(long pos) {
super.onSeekTo(pos);
}
@Override
public void onSetRating(Rating rating) {
super.onSetRating(rating);
}
}
);
}
正如作者所指出的,实际的媒体播放器实例化和实现并不存在,但是:“现在我们在锁屏和通知抽屉中有了一个完全工作的MediaStyle通知,它利用MediaSession进行播放控制。享受吧!”
我做了几处修改。主要更改是方法initMediaSessions()。添加了用于实例化和初始化媒体播放器的代码。这是添加prepareAsync()和setOnPreparedListener()调用的地方。 还对onPlay()和onPause()回调进行了更改,以包括媒体播放器控制方法
public void initMediaSessions () {
Uri uri = Uri.parse("http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8" );
//String fileName = "android.resource://" + getPackageName() + "/" + R.raw.georgeharrisonlivinginthematerialworld;
//Uri uri = Uri.parse(fileName);
try {
mMediaPlayer = new MediaPlayer();
} catch (IllegalArgumentException e) {
Toast.makeText(getApplicationContext(), "IllegalArgumentException", Toast.LENGTH_LONG).show();
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(), "SecurityException", Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException", Toast.LENGTH_LONG).show();
}
try {
mMediaPlayer.setDataSource(this, uri);
} catch (IllegalArgumentException e) {
Toast.makeText(getApplicationContext(), "IllegalArgumentException", Toast.LENGTH_LONG).show();
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(), "SecurityException", Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnPreparedListener(this);
try {
mMediaPlayer.prepareAsync();
} catch (IllegalArgumentException e) {
Toast.makeText(getApplicationContext(), "IllegalArgumentException", Toast.LENGTH_LONG).show();
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(), "SecurityException", Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException", Toast.LENGTH_LONG).show();
}
mManager= (MediaSessionManager)getSystemService(Context.MEDIA_SESSION_SERVICE);
mSession = new MediaSession(getApplicationContext(), "simple player session");
mController =new MediaController(getApplicationContext(), mSession.getSessionToken());
mSession.setCallback(new MediaSession.Callback(){
@Override
public void onPlay() {
super.onPlay();
Log.e("MediaPlayerService", "onPlay");
if(first_time_through == true)
{
first_time_through = false;
}
else {
try {
mMediaPlayer.start();
} catch (IllegalArgumentException e) {
Toast.makeText(getApplicationContext(), "IllegalArgumentException", Toast.LENGTH_LONG).show();
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(), "SecurityException", Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException", Toast.LENGTH_LONG).show();
}
}
buildNotification(generateAction(android.R.drawable.ic_media_pause, "Pause", ACTION_PAUSE));
}
@Override
public void onPause() {
super.onPause();
mMediaPlayer.pause();
Log.e( "MediaPlayerService", "onPause");
buildNotification(generateAction(android.R.drawable.ic_media_play, "Play", ACTION_PLAY));
}
@Override
public void onSkipToNext() {
super.onSkipToNext();
Log.e( "MediaPlayerService", "onSkipToNext");
//Change media here
buildNotification( generateAction( android.R.drawable.ic_media_pause, "Pause", ACTION_PAUSE ) );
}
@Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
Log.e( "MediaPlayerService", "onSkipToPrevious");
//Change media here
buildNotification( generateAction( android.R.drawable.ic_media_pause, "Pause", ACTION_PAUSE ) );
}
@Override
public void onFastForward() {
super.onFastForward();
Log.e( "MediaPlayerService", "onFastForward");
//Manipulate current media here
}
@Override
public void onRewind() {
super.onRewind();
Log.e( "MediaPlayerService", "onRewind");
//Manipulate current media here
}
@Override
public void onStop() {
super.onStop();
Log.e( "MediaPlayerService", "onStop");
//Stop media player here
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel( 1 );
Intent intent = new Intent( getApplicationContext(), MediaPlayerService.class );
stopService( intent );
}
@Override
public void onSeekTo(long pos) {
super.onSeekTo(pos);
}
@Override
public void onSetRating(Rating rating) {
super.onSetRating(rating);
}
}
);
}
该活动使用“播放意图”操作启动MediaPlayerService:
intent.setAction( MediaPlayerService.ACTION_PLAY );
第一次通过逻辑添加到onPlay()回调中,以防止在执行onPrepared()回调之前调用mmediplayer.start()方法。以下内容已添加到MediaPlayerService类:
public static boolean first_time_through = true;
onPrepared()回调也被添加到MediaPlayerService中
/** Called when MediaPlayer is ready */
public void onPrepared(MediaPlayer player) {
try {
mMediaPlayer.start();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "IllegalStateException in onPrepared", Toast.LENGTH_LONG).show();
}
}
由于我尝试使用HLS源执行此操作,因此在AndroidManifest.xml文件中添加了以下行:
<uses-permission android:name="android.permission.INTERNET" />
<permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
当我在我的三星Galaxy S5上使用相同的音频源时,使用简化的(API 4.4.2版本的应用程序),音频播放效果很好。此外,正如预期的那样,当从Safari启动时,相同的HLS源可以正常运行。我认为通过模拟器查看HLS回放不会获得太多好处
再次感谢你,亲爱的
Jim试图使用简单服务而不是IntentService?这里真的不需要IntentService,如果您真的需要知道原因,请参阅IntentService.javapskink中的ServiceHandler类是如何实现的。听起来你在极力推荐使用这项服务。我将把代码重写为so,然后将结果作为后续发布。我还将按照您的建议介绍IntentService的实现。我要去服务中心了。我对Android、Java和stackoverflow的世界比较陌生。如果我对使用服务的实现有疑问,我会在这个线程中发布它吗?再次感谢。是的,你可以在这里问。服务有效吗?
<permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
01-10 01:25:22.074 1219-1237/system_process I/ActivityManager﹕ Waited long enough for: ServiceRecord{3ca21a0b u0 com.google.android.gms/.wearable.service.WearableService}
01-10 01:25:26.204 931-1216/? I/AudioFlinger﹕ BUFFER TIMEOUT: remove(4096) from active list on thread 0xb62b8000
01-10 01:25:34.675 2076-2100/com.android.calendar D/InitAlarmsService﹕ Clearing and rescheduling alarms.
01-10 01:25:59.696 1219-1232/system_process I/MediaFocusControl﹕ AudioFocus abandonAudioFocus() from android.media.AudioManager@1c78d923com.android.music.MediaPlaybackService$3@5af4e20