我正在创建一个简单的音频播放器。除了MapChangeListener之外,侦听器事件很好。运行App时,MapChangeListener(元数据)的侦听器将同时触发并获取最后一个元数据轨道。
例如:
我想这样做:
我已经读过媒体的getMetadata()
方法在App的同一个线程中执行,因此我无法将监听器添加到 setOnPlaying(Runnable())中的元数据方法。
还在Play事件中使用 Platform.runLater()进行了尝试,但是简单无效。
我感谢任何帮助。感谢。
我的听众
final public class MetadataListener implements MapChangeListener<String, Object> {
private PlayerControl gui;
private static int count;
public MetadataListener(PlayerControl gui) {
this.gui = gui;
}
@Override
public void onChanged(Change<? extends String, ? extends Object> change) {
count++;
if(change.wasAdded()) {
handleMetadata(change.getKey().toString(), change.getValueAdded());
}
}
private void handleMetadata(String key, Object value) {
if(key.equals("title"))
gui.getLblTitle().setText(value.toString());
if(key.equals("artist"))
gui.getLblArtist().setText(value.toString());
if(key.equals("album"))
gui.getLblAlbum().setText(value.toString());
if(key.equals("year"))
gui.getLblYear().setText(value.toString());
if(key.equals("image"))
gui.getImgViewAlbum().setImage((Image) value);
}
}
我的播放器
public void createMediaList() {
for(String file : filterFiles()) {
playList.add(createPlayer(file));
}
if(playList.isEmpty()) {
System.out.println("No se han encontrado archivos multimedia");
Platform.exit();
return;
}
}
private MediaPlayer createPlayer(String filePath) {
Media media = new Media(new File(dir.toString()+"/"+filePath).toURI().toString());
MediaPlayer player = new MediaPlayer(media);
this.attachListeners(player);
return player;
}
private void attachListeners(MediaPlayer player) {
player.setOnPlaying(() -> {
duration = player.getMedia().getDuration();
gui.getLblTotalDuration().setText(formatCurrentDuration(duration));
gui.getBtnPlayPause().setText(" | | ");
updateValues();
});
player.currentTimeProperty().addListener((observable, oldValue, newValue) -> {
updateValues();
});
player.getMedia().getMetadata().addListener(metadataListener);
player.setOnEndOfMedia(() -> {
player.stop();
this.nextMedia();
});
//player.setOnStopped( () -> player.getMedia().getMetadata().removeListener(metadataListener));
player.setOnPaused( () -> gui.getBtnPlayPause().setText("►"));
player.setOnError(() -> System.out.println("Ha ocurrido un error"));
}
protected void updateValues() {
Label lblCurrentTime = gui.getLblCurrentTime();
Label lblTotalDuration = gui.getLblTotalDuration();
Slider sldPlayer = gui.getSldPlayer();
//Slider sldVolume = gui.getSldVolume();
if(lblCurrentTime != null && lblTotalDuration != null && sldPlayer != null && /*sldVolume != null &&*/ duration != null) {
Platform.runLater(() -> {
Duration currentTime = this.playList.get(currentMediaIndex).getCurrentTime();
lblCurrentTime.setText(formatCurrentDuration(currentTime));
sldPlayer.setDisable(duration.isUnknown());
if(!sldPlayer.isDisabled() && duration.greaterThan(Duration.ZERO) && !sldPlayer.isValueChanging()) {
sldPlayer.setValue(currentTime.divide(duration).toMillis() * 100.0);
}
});
}
}
答案 0 :(得分:1)
原因
为所有曲目
触发MapChangeListener我的应用程序中显示的元数据是最后一首曲目。
在您的代码中:
for(String file : filterFiles()) {
playList.add(createPlayer(file));
}
private MediaPlayer createPlayer(String filePath) {
Media media = new Media(new File(dir.toString()+"/"+filePath).toURI().toString());
MediaPlayer player = new MediaPlayer(media);
this.attachListeners(player);
return player;
}
启动应用程序时,您将为播放列表中的所有曲目创建媒体播放器并为其添加侦听器。一旦为每个轨道重新获取元数据,所有标签都会被更新,并且这就是您只能看到最后一个轨道元数据的原因。
首先,检索有效媒体播放器列表,并调用第一首曲目:
private final List<MediaPlayer> playList = new ArrayList<>();
public void createMediaList() {
for(String file : filterFiles()) {
MediaPlayer player=createPlayer(file);
if(player!=null){
playList.add(player);
}
}
if(playList.isEmpty()) {
System.out.println("No se han encontrado archivos multimedia");
Platform.exit();
return;
}
// start first track
nextMedia();
}
,其中
private MediaPlayer createPlayer(String filePath) {
try{
Media media = new Media(new File(dir+"/"+filePath).toURI().toString());
MediaPlayer player=new MediaPlayer(media);
return player;
} catch(MediaException me){
System.out.println("MediaException "+me);
}
return null;
}
由于并非每个文件都有效,因此在try catch中围绕媒体播放器创建很方便。
现在,nextMedia()
只检索单个轨道的媒体播放器,并附加监听器。
编辑:通常,在创建媒体播放器时,使用setOnReady()
开始播放很方便,但在这种情况下,所有曲目的媒体播放器都是在开始时,球员们已准备好了。
private void nextMedia(){
MediaPlayer player=playList.get(currentMediaIndex++);
attachListeners(player);
if(player!=null){
player.play();
} else {
nextMedia();
}
}
当曲目准备就绪时,将检索所有元数据并更新标签:
private void attachListeners(MediaPlayer player) {
...
player.getMedia().getMetadata().addListener(metadataListener);
...
player.setOnEndOfMedia(() -> {
player.getMedia().getMetadata().removeListener(metadataListener);
player.stop();
nextMedia();
});
}
当曲目结束时,您的听众将再次拨打nextMedia()
。