安卓MediaPlayer错误(1,-4)prepareAsync方法

3
我在prepareAsync方法中遇到了一个错误(1,-4)。文档指明这是“文件格式不正确”的问题(对吗?),但是该文件是mp3格式的。此外,在旧版本的软件中,当mediaplayer在另一个Activity中被调用时,同样的文件可以被播放。 我不知道如何解决这个问题,所以来寻求帮助。
下面是应用程序的代码:
SingletonMediaPlayer将管理一个mediaplayer对象,该对象作为应用程序中的单例使用。
public class SingletonMediaPlayer {

    private static SingletonMediaPlayer instance;
    private MediaPlayer mp;
    private int buffer_state;

    private SingletonMediaPlayer() {
        Log.d("SMP","Creating new media player");
        this.mp = new MediaPlayer();
        this.buffer_state = 0;
    }

    public static SingletonMediaPlayer getInstance() {
        if (instance == null) {
            instance = new SingletonMediaPlayer();
        }

        return instance; 
    }

    public void play(String path, final TextView tv_messaging){             
        if(this.mp.isPlaying()){
            Log.d("SMP","Player is playing, now I'll stop and reset it");
            this.mp.stop();
            this.mp.reset();
            this.mp.release();
        }

        Log.d("SMP","Set audio stream type");
        this.mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
        try {

            Log.d("SMP","Set data source");
            this.mp.setDataSource(path);
            Log.d("SMP","Prepare async");
            this.mp.prepareAsync();
            Log.d("SMP","Done!");
            tv_messaging.setText("Connecting to the server...please wait");
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            tv_messaging.setText(e.toString());
            Log.e("SMP","IllegalArgumentException");
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            tv_messaging.setText(e.toString());
            Log.e("SMP","SecurityException");
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            tv_messaging.setText(e.toString());
            Log.e("SMP","IllegalStateException");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            tv_messaging.setText(e.toString());
            Log.e("SMP","IOException");
        }catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            tv_messaging.setText(e.toString());
            Log.e("SMP","Generic Exception");
        }
    }

    public void checkBufferState(final TextView tv_buffer_message){
        final SingletonMediaPlayer self = this;

        Log.d("SMP","  Set on prepared listener");
        this.mp.setOnErrorListener(new OnErrorListener(){

            @Override
            public boolean onError(MediaPlayer mp, int arg1, int arg2) {
                // TODO Auto-generated method stub
                return false;
            }

        });
        this.mp.setOnPreparedListener(new OnPreparedListener() {
            public void onPrepared(MediaPlayer mPlayer) {
                OnBufferingUpdateListener lis = new OnBufferingUpdateListener(){
                    public void onBufferingUpdate(MediaPlayer mPlayer, int percent) {
                        Log.d("SMP","      Mediaplayer ready (preparation done). Inside buffer listener");
                        self.buffer_state = percent;
                        if(tv_buffer_message != null){
                            tv_buffer_message.setText(percent+"%");
                        }
                    }
                };

                Log.d("SMP","    Mediaplayer ready (preparation done). Installing buffer listener");
                mPlayer.setOnBufferingUpdateListener(lis);
                Log.d("SMP","    Mediaplayer ready (preparation done). Starting reproduction");
                mPlayer.start();
                Log.d("SMP","    Mediaplayer ready (preparation done). Done!");
            }
        });
    }

    public int getBufferState(){
        return this.buffer_state;
    }
}

我正在动态创建按钮,当按钮被点击时应该播放mp3音频。因此,在用于创建按钮的循环之前,我有以下代码:
final SingletonMediaPlayer mediaPlayer = SingletonMediaPlayer.getInstance();
mediaPlayer.checkBufferState(tv_sel_ep);

而且,对于每个按钮,我都有一个
button.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        mediaPlayer.play(link, Text_view_used_to_show_error);
    }
});

日志

02-15 14:35:24.165: D/dalvikvm(1415): GC_EXTERNAL_ALLOC freed 58K, 52% free 2633K/5379K, external 391K/517K, paused 87ms
02-15 14:35:25.705: D/NetworkActivity(1415): Starting SelectEpisodeActivity
02-15 14:35:25.995: D/SMP(1415): Creating new media player
02-15 14:35:26.005: D/SMP(1415):   Set on prepared listener
02-15 14:35:28.745: W/KeyCharacterMap(1415): No keyboard for id 0
02-15 14:35:28.745: W/KeyCharacterMap(1415): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
02-15 14:35:28.745: I/qqqqqqqqqqqqq(1415): qqqqqqqqqqqqqqqqqqqq
02-15 14:35:29.235: D/dalvikvm(1415): GC_CONCURRENT freed 307K, 53% free 2669K/5639K, external 477K/989K, paused 8ms+12ms
02-15 14:35:30.275: D/NetworkActivity(1415): Starting SelectEpisodeActivity
02-15 14:35:30.415: D/SMP(1415):   Set on prepared listener
02-15 14:35:32.485: D/SMP(1415): Set audio stream type
02-15 14:35:32.485: D/SMP(1415): Set data source
02-15 14:35:32.785: D/SMP(1415): Prepare async
02-15 14:35:32.785: D/SMP(1415): Done!
02-15 14:35:32.885: W/MediaPlayer(1415): info/warning (1, 26)
02-15 14:35:32.885: I/MediaPlayer(1415): Info (1,26)
02-15 14:35:32.885: E/MediaPlayer(1415): error (1, -4)
02-15 14:35:32.885: E/MediaPlayer(1415): Error (1,-4)

编辑:Dave回答后的新日志

02-16 14:35:11.265: D/dalvikvm(12723): GC_EXTERNAL_ALLOC freed 59K, 52% free 2633K/5379K, external 391K/517K, paused 133ms
02-16 14:35:13.265: D/NetworkActivity(12723): Starting SelectEpisodeActivity
02-16 14:35:13.405: D/SMP(12723): Creating new media player
02-16 14:35:13.415: D/SMP(12723):   Set on prepared listener
02-16 14:35:17.365: D/SMP(12723): Set audio stream type
02-16 14:35:17.365: D/SMP(12723): Set data source
02-16 14:35:17.435: D/SMP(12723): Prepare async
02-16 14:35:17.435: D/SMP(12723): Done!
02-16 14:35:17.445: W/MediaPlayer(12723): info/warning (1, 26)
02-16 14:35:17.445: E/MediaPlayer(12723): error (1, -4)
02-16 14:35:17.465: I/MediaPlayer(12723): Info (1,26)
02-16 14:35:17.465: E/MediaPlayer(12723): Error (1,-4)

感谢您的帮助。
1个回答

1

几点提醒:

1)如果您希望 MediaPlayer 在释放之后仍处于可用状态,则不应调用 release()。 -4错误(如果我记得正确)是无效的状态转换,尝试使用已释放的 MediaPlayer 应产生恰好这个错误。

2)您可以在创建 MediaPlayer 时设置 onPrepared onError onBufferingUpdate 侦听器。您现在正在做的事情似乎很笨拙,也是不必要的。

3)遇到Android问题时,请发布logcat输出。

如果只执行第一步,则可能会得到可行的结果。不过,在实际使用将调用回调的方法之前设置侦听器是个好主意。

编辑:

private static SingletonMediaPlayer instance;
private MediaPlayer mp;
private int buffer_state;
// Add a member for the TextView
private TextView tv_buffer_message;

private SingletonMediaPlayer() {
    Log.d("SMP","Creating new media player");
    mp = new MediaPlayer();
    Log.d("SMP","Set audio stream type");
    mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mp.setOnErrorListener(new OnErrorListener(){
        @Override
        public boolean onError(MediaPlayer mp, int arg1, int arg2) {
            // YOU SHOULD REALLY DO SOMETHING HERE!!! IT COULD BE INFORMATIVE!!!
            return false;
        }
    });
    Log.d("SMP","  Installing buffer listener");
    mp.setOnBufferingUpdateListener(new OnBufferingUpdateListener(){
        public void onBufferingUpdate(MediaPlayer mPlayer, int percent) {
            Log.d("SMP","      Mediaplayer ready (preparation done). Inside buffer listener");
            buffer_state = percent;
            if(tv_buffer_message != null){
                tv_buffer_message.setText(percent+"%");
            }
        }
    };
    Log.d("SMP","  Set on prepared listener");
    mp.setOnPreparedListener(new OnPreparedListener() {
        public void onPrepared(MediaPlayer mPlayer) {
            Log.d("SMP","    Mediaplayer ready (preparation done). Starting reproduction");
            mPlayer.start();
            Log.d("SMP","    Mediaplayer ready (preparation done). Done!");
        }
    });
    buffer_state = 0;
}

// Remove the checkBufferState method and call the following in its place:
public setBufferMessageView(TextView tv) {
    tv_buffer_message = tv;
}

// getInstance, play, and getBufferState can stay the same, except remove the call to release

当我自己尝试解决错误时,我添加了release()方法;如果我将其删除,没有任何变化。我不明白第二点,什么是不必要的?第三点你是对的,我在发布问题时忘记了日志。 - Max Markson
如果您在创建MediaPlayer时只是简单地添加监听器,那么整个checkBufferState方法都是不必要的。请注意日志中准备好的监听器被设置了多次(这可能是问题所在,因为准备好的回调会调用start函数)。我将编辑我的答案以说明我认为更好的方法。 - Dave
准备好的监听器只设置一次,当我测试应用程序时,为了获取日志文件,我点击了一个没有链接的按钮,所以无法重现正确的错误。字符串02-15 14:35:28.745: I/qqqqqqqqqqqqq(1415): qqqqqqqqqqqqqqqqqqqq的意思是“物理返回按钮被按下”。我根据您的指导修改了我的代码,但它仍然不起作用(请查看新的日志)。 - Max Markson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接