如何处理 MediaPlayer 和 BaseAdapter

How to deal with MediaPlayer and BaseAdapter

我正在实施来自 this tutorial 的音乐应用程序。

有一个BaseAdapterclass用来显示曲目列表,还有一个MusicPlayerclass用来播放音乐。两者都是我的主要变量 activity class.

public class MainActivity extends Activity implements MediaPlayerControl{
       private MediaPlayer musicSrv;
       private BaseAdapter songAdt;
       ...

MusicPlayer 在当前曲目结束时播放下一首曲目。向 BaseAdapter 发送消息以更改每个新播放曲目的显示(例如更改当前曲目的颜色)的最佳方法是什么?

编辑

根据评论,使用一个接口good似乎是个不错的选择。有人可以写一个详细的答案来解释如何做吗?谢谢

BaseAdapter 的方法 getView() 方法将为您提供视图,您应该通过在列表中设置一个变量来更改当前轨道的颜色,并在未设置变量时将该颜色重置为默认值。

if (is this the current playing track) {
    // Set the color of the view.
} else {
    // Set the color to default.
}

如果您目前已经实现了这个逻辑,那么每当您更改当前曲目以及列表中跟踪当前播放媒体的变量时,一个简单的 songAdt.notifyDataSetChanged() 将要求再次调用 BaseAdapter 并将根据新数据设置视图。更深入的了解ListView可以参考this talk。我会帮你的。

最好考虑使用 RecyclerView 培训自己,这是目前的。 ListView 是一段可怕的过去。

public class Activity implements SongChangedListener {
...
    @Override
    onCreate() {
        ....
        PlayerManager pManager = new PlayerManager();
    }

    onResume() {
        pManager.setListener(this);
    }

    onPause() {
        pManager.setListener(null);
    }

    @Override
    void songChanged (MediaId idOfSong) {
         if (getActivity == null)  //If you received a callback after activity was killed.
             return;
        // Change the current song as not playing in List. (for your adapter)
        // Change the idOfSong to currently playing in List (for your adapter).
        // change currentSong = idOfSong;
        // notify that the data in List has changed (songAdt.notifyDataSetChanged)
    }

}

并且在您的 PlayerManager 中,您可以创建接口,或者为接口创建一个单独的 class,无论您如何发送接口实例。

public class PlayerManager {
    ...
    private SongChangedListener mListener;
    ...

    public PlayerManager() {
    }

    public void setListener(SongChangedListener listener) {
        mListener = listener;
    }

    public interface SongChangedListener {
       void songChanged(MediaId idOfSong);
    }

    ...
    public void playSong() { 
       ...
       if (mListener != null)
           mListener.songChanged(idOfNextSong);
       ...
    }

在您的回答中,您将 activity 传递到您的服务中,这在很多方面都让人感觉不对。如果你想实现 activity 和服务之间的通信,还有很多其他的方法可以做到这一点。通常我将 Messenger 与 Handler 结合使用。我会提供更多细节,但如果您在文档和其他答案中探索它会更有益。一旦您了解了 Messengers 的工作原理,就很容易实施。

此外,如果您正在寻找功能完备的 MediaPlayer 应用程序,您的实现将需要更多的锅炉代码。此外,您还必须处理 MediaButton 的点击(如果有人在他们的蓝牙耳机或手表上点击 play/pause)。最好是MediaSessionCompat is a better implementation. You can also refer the following open Source MediaPlayer, which implements all the minimum required functionalities pretty nicely android-UniversalMusicPlayer.

在您的音乐曲目模型中维护一个变量class,它指示这首歌曲是否处于播放模式。

检查您 getView() 中的值并根据它进行编码。

if(model.is_playing)
   //change your code for playing song
else
   //rest songs which are not playing

现在,无论您是手动还是自动更改歌曲,都请更改 is_playing 值,将其从之前的曲目中取消设置并将其设置为当前播放的曲目。

您不需要实现自己的回调接口。当播放声音终止时,Mediaplayer 已经有一个 oncompletionlistener。所以你只需要在 oncompletion 方法中刷新你的适配器

public class MainActivity extends Activity implements MediaPlayerControl, MediaPlayer.OnCompletionListener{
    private MediaPlayer musicSrv;
    private BaseAdapter songAdt;


    @Override
    public void onCreate() {
        musicSrv.setOnCompletionListener(this);
    }

    @Override
    public void onCompletion(MediaPlayer musicPlayer) {
        songAdt.notifyDataSetChanged();
    }
}

感谢评论,我设法实现了一个带有接口的解决方案。

这是我的 Main activity class,每次更改歌曲时都会刷新 BaseAdapater:

public class MainActivity extends Activity implements MusicService.SongChangedListener {
      private MediaPlayer musicSrv;
      private BaseAdapter songAdt;
      ...

      @Override
      public void songChanged(Song currentSong){
           songAdt.notifyDataSetChanged(); // refresh view
      }

还有我的 MusicService class:

public class MusicService extends Service implements MediaPlayer.OnPreparedListener{
...
private MainActivity activity;
...

public void setActivity(MainActivity act){
    //set the activity
    activity = act;
}

public interface SongChangedListener {
     void songChanged(Song song);
}
...
public void playSong(){ 
       // this function is called each time a new song is played
       activity.songChanged(playSong);
       ...
}