所以我一直在寻找这个一周,并且阅读虽然每个问题都很相似,但似乎没有人像我一样问同样的问题(尝试逆向工程其他解决方案类似于我想要的但没有成功.
解释了穴居人风格:我正在尝试使用元数据创建列表.
>我打开多个对话框并选择多个mp3
>我把文件放在一个ArrayList< File>
>我循环使用增强的for循环文件,并使用媒体变量提取元数据
>元数据的信息(如“艺术家”)是我想要保存在ArrayList中的例子
问题是,只有在增强循环结束后,侦听器才能正常工作
的ArrayList<字符串>有一个没有任何东西的物体
这是一个示例:
ArrayList<String> al; String path; public void open(){ files=chooser.showOpenMultipleDialog(new Stage()); for( File f:files){ path=f.getPath(); Media media = new Media("file:/"+path.replace("\\","/").replace(" ","%20")); al= new ArrayList<String>(); media.getMetadata().addListener(new MapChangeListener<String,Object>() { public void onChanged(Change<? extends String,? extends Object> change) { if (change.wasAdded()) { if (change.getKey().equals("artist")) { al.add((String) change.getValueAdded()); } } } }); }//close for loop //then i want to see the size of al like this system.out.println(al.size()); //then it returns 1 no matter how much file i selected //when i system out "al" i get an empty string
解决方法
通过添加侦听器来读取媒体源元数据的另一种方法是在媒体播放器中提取该信息.setOnReady();这是java控制器类的一个示例部分
public class uiController实现Initializable {
@FXML private Label label; @FXML private ListView<String> lv; @FXML private AnchorPane root; @FXML private Button button; private ObservableList<String> ol= FXCollections.observableArrayList(); private List<File> selectedFiles; private final Object obj= new Object(); @Override public void initialize(URL url,ResourceBundle rb) { assert button != null : "fx:id=\"button\" was not injected: check your FXML file 'ui.fxml'."; assert label != null : "fx:id=\"label\" was not injected: check your FXML file 'ui.fxml'."; assert lv != null : "fx:id=\"lv\" was not injected: check your FXML file 'ui.fxml'."; assert root != null : "fx:id=\"root\" was not injected: check your FXML file 'ui.fxml'."; // initialize your logic here: all @FXML variables will have been injected lv.setItems(ol); } @FXML private void open(ActionEvent event) { FileChooser.ExtensionFilter extention= new FileChooser.ExtensionFilter("Music Files","*.mp3","*.m4a","*.aif","*.wav","*.m3u","*.m3u8"); FileChooser fc= new FileChooser(); fc.setInitialDirectory(new File(System.getenv("userprofile"))); fc.setTitle("Select File(s)"); fc.getExtensionFilters().add(extention); selectedFiles =fc.showOpenMultipleDialog(root.getScene().getWindow()); if(selectedFiles != null &&!selectedFiles.isEmpty()){ listFiles(); } } /** * Convert each fie selected to its URI */ private void listFiles(){ try { for (File file : selectedFiles) { readMetaData(file.toURI().toString()); synchronized(obj){ obj.wait(100); } } } catch (InterruptedException ex) { } System.gc(); } /** * Read a Media source Metadata * Note: Sometimes the was unable to extract the Metadata especially when * i have selected large number of files reasons i don't known why * @param mediaURI Media file URI */ private void readMetaData(String mediaURI){ final MediaPlayer mp= new MediaPlayer(new Media(mediaURI)); mp.setOnReady(new Runnable() { @Override public void run() { String artistName=(String) mp.getMedia().getMetadata().get("artist"); ol.add(artistName); synchronized(obj){//this is required since mp.setOnReady creates a new thread and our loopp in the main thread obj.notify();// the loop has to wait unitl we are able to get the media Metadata thats why use .wait() and .notify() to synce the two threads(main thread and MediaPlayer thread) } } }); }
}
所做的一些更改是使用ObservableList来存储元数据中的艺术家名称
在代码中你会发现这个
synchronized(obj){ obj.wait(100); }
我这样做是因为mediaplayer .setOnReady()创建了一个新线程并且循环在主应用程序线程中.循环必须等待一段时间才能创建另一个线程并且我们能够提取元数据,并且.setOnReady()有一个
synchronized(obj){ obj.notify; }
唤醒主线程因此循环能够移动到下一个项目
我承认这可能不是解决此问题的最佳解决方案,但欢迎任何有更好方法从文件列表中读取JavaFx媒体元数据的人
完整的Netbeans项目可以在这里找到https://docs.google.com/file/d/0BxDEmOcXqnCLSTFHbTVFcGIzT1E/edit?usp=sharing
plus使用JavaFX创建了一个小型MediaPlayer应用程序,该应用程序使用了元数据https://docs.google.com/file/d/0BxDEmOcXqnCLR1Z0VGN4ZlJkbUU/edit?usp=sharing