11

我对以下代码有问题。我在 MediaController 上调用了 setPrevNextListener 并为 Prev 和 Next 定义了两个 onClickListener。当我单击下一个按钮而不是前进一首曲目时,我前进了两首曲目。这似乎是由于 onCompletion 以某种方式被调用的事实。MediaPlayer.reset() 是否调用 onCompletion?我已经包含了 logcat 输出和我的代码。如果我做错了什么,请告诉我。提前致谢。

日志猫:

02-24 00:36:34.826: D/MP(6675): Next Button Clicked, index was: 0
02-24 00:36:34.837: D/MP(6675): About to call Reset()
02-24 00:36:34.906: D/MP(6675): Inside setUpPlayer
02-24 00:36:34.917: D/MP(6675): Called setDataSource with index: 1
02-24 00:36:34.917: D/MP(6675): Leaving setUpPlayer
02-24 00:36:34.917: D/MP(6675): About to call prepareAsync()
02-24 00:36:34.937: D/MP(6675): Leaving next button
02-24 00:36:35.226: E/MediaPlayer(6675): Attempt to call getDuration without a valid mediaplayer
02-24 00:36:35.226: E/MediaPlayer(6675): error (-38, 0)
02-24 00:36:35.276: E/MediaPlayer(6675): Error (-38,0)
02-24 00:36:35.287: D/MP(6675): Inside onCompletion
02-24 00:36:35.337: D/MP(6675): About to call Reset()
02-24 00:36:35.347: D/MP(6675): Inside setUpPlayer
02-24 00:36:35.356: D/MP(6675): Called setDataSource with index: 2
02-24 00:36:35.356: D/MP(6675): Leaving setUpPlayer
02-24 00:36:35.356: D/MP(6675): About to call prepareAsync()
02-24 00:36:35.377: D/MP(6675): Leaving onCompletion
02-24 00:36:36.517: D/MP(6675): Inside onPrepared, index is: 2
02-24 00:36:36.577: D/MP(6675): Leaving onPrepared

代码:

public class MusicPlayerActivity extends Activity implements OnPreparedListener, OnCompletionListener, MediaController.MediaPlayerControl {

    private MediaPlayer mp;
    private MediaController mc;
    private SonarDatabase db;
    private SubsonicAPIConnector sonic;
    ArrayList<String> songs;
    int index = 0;
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.music_player);

        // Get params from intent
        Intent i = getIntent();
        String albumId = i.getStringExtra("albumId");
        String artistId = i.getStringExtra("artistId");
        String albumName = i.getStringExtra("albumName");
        String songName = i.getStringExtra("songName");
        String songId = i.getStringExtra("songId");
        String coverArt = "al-"+albumId+".jpeg";
        String duration = i.getStringExtra("duration");
        Log.d("MP", "results: albumName:" + albumName + ", songName: " + songName + ", songId: " 
                + songId + ", duration: " + duration + ", coverArt: " + coverArt + ", artistId: "
                + artistId + ", albumId: " + albumId);
        db = new SonarDatabase(getApplicationContext());
        sonic = new SubsonicAPIConnector(db.getURL(), db.getUsername(), db.getPassword());
        String artistName = db.getArtistNameById(artistId);
        setTitle("Now Playing");
        songs = db.getSongListForAlbum(albumId);
        index = songs.indexOf(songId); 
        Log.d("MP", "songid: " + songId + ", index: " + index);
        // Update text views with song information
        TextView txtArtist = (TextView) findViewById(R.id.txtArtistName);
        txtArtist.setText(artistName);
        TextView txtAlbum = (TextView) findViewById(R.id.txtAlbumName);
        txtAlbum.setText(albumName);
        TextView txtSong = (TextView) findViewById(R.id.txtSongName);
        txtSong.setText(songName);

        // Show the album art
        File img = new File(this.getFilesDir()+"/covers/"+coverArt);
        if(img.exists()) {
            Log.d("MP", "Found image at: " + img.toString());
            ImageView imgView = (ImageView) findViewById(R.id.cover_art);
            imgView.setImageBitmap(BitmapFactory.decodeFile(img.getPath()));
        } else {
            Log.d("MP", "Couldn't find image: " + img.toString());
        }


        // Create the media player and controller
        mp = new MediaPlayer();
        mp.setOnPreparedListener(this);
        mp.setOnCompletionListener(this);
        mc = new NonHidingMediaController(this);
        mc.setPrevNextListeners(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // next button clicked
                Log.d("MP", "Next Button Clicked, index was: " + index);
                playNextTrack();
                Log.d("MP", "Leaving next button");
            }
        }, new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // previous button clicked
                Log.d("MP", "Previous button clicked, index was: " + index);
                if(mp.isPlaying() && mp.getCurrentPosition() < 2000 && index != 0) {
                    Log.d("MP", "Start the prior song.");
                    playPreviousTrack();
                } else {
                    Log.d("MP", "Restart this song.");
                    restartCurrentTrack();
                }   
                Log.d("MP", "Leaving previous button");
            }
        });
        mc.setMediaPlayer(this);
        setUpPlayer();
        Log.d("MP", "About to call prepareAsync()");
        mp.prepareAsync();
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        Log.d("MP", "Inside onCompletion");
        //TODO add code for scrobbling here.
        playNextTrack();
        Log.d("MP", "Leaving onCompletion");
    }


    private void playNextTrack() {
        index++;
        TextView txtSong = (TextView) findViewById(R.id.txtSongName);
        txtSong.setText(db.getSongNameById(songs.get(index)));
        Log.d("MP", "About to call Reset()");
        mp.reset();
        setUpPlayer();
        Log.d("MP", "About to call prepareAsync()");
        mp.prepareAsync();
    }

    private void playPreviousTrack() {
        index--;
        TextView txtSong = (TextView) findViewById(R.id.txtSongName);
        txtSong.setText(db.getSongNameById(songs.get(index)));
        Log.d("MP", "About to call Reset()");
        mp.reset();
        setUpPlayer();
        Log.d("MP", "About to call prepareAsync()");
        mp.prepareAsync();

    }

    private void restartCurrentTrack() {
        mp.seekTo(0);
    }

    public void onPrepared(MediaPlayer mp) {
        Log.d("MP", "Inside onPrepared, index is: " + index);
        mc.setMediaPlayer(this);
        mc.setAnchorView(findViewById(R.id.music_player_view));
        mp.start();
        handler.post(new Runnable() {
            public void run() {
                mc.setEnabled(true);
                mc.show();
            }
        });
        Log.d("MP", "Leaving onPrepared");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_music_player, menu);
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("MP", "OnTouchEvent called");
        mc.show();
        return false;
    }

    private void setUpPlayer() {
        Log.d("MP", "Inside setUpPlayer");
        mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
        try {
            mp.setDataSource(sonic.streamString("&id=" + songs.get(index)));
            Log.d("MP", "Called setDataSource with index: " + index);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Log.d("MP", "Leaving setUpPlayer");
    }

    @Override
    protected void onStop() {
        super.onStop();
        mc.hide();
        mp.stop();
        mp.release();
    }

    public void start() {
        mp.start();
    }

    public void pause() {
        mp.pause();
    }

    public int getDuration() {
        return mp.getDuration();
    }

    public int getCurrentPosition() {
        return mp.getCurrentPosition();
    }

    public void seekTo(int i) {
        mp.seekTo(i);
    }

    public boolean isPlaying() {
        return mp.isPlaying();
    }

    public int getBufferPercentage() {
        return 0;
    }

    public boolean canPause() {
        return true;
    }

    public boolean canSeekBackward() {
        return true;
    }

    public boolean canSeekForward() {
        return true;
    }

    public class NonHidingMediaController extends MediaController {
        public NonHidingMediaController(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public NonHidingMediaController(Context context, boolean useFastForward) {
            super(context, useFastForward);
        }

        public NonHidingMediaController(Context context) {
            super(context);
        }

        @Override
        public void show(int timeout) {
            super.show(0);
        }

    }


}
4

2 回答 2

30

我对 android 源代码做了一些挖掘,发现任何未处理的错误都会导致 MediaPlayer 调用 onCompletion 处理程序。在这种情况下,您似乎在空闲、初始化或错误状态下调用 getDuration。可能从媒体控制器内部。我建议在任何调用 getDuration 的地方之前添加一些 Log.d() 以查看导致问题的调用在哪里。

于 2013-04-11T18:16:33.253 回答
17

添加 MediaPlayer.OnErrorLisener 并从覆盖的方法返回 true

mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                    @Override
                    public boolean onError(MediaPlayer mp, int what, int extra) {
                        return true;
                    }
                });
于 2016-07-20T07:02:01.823 回答