2013-01-12 40 views
5

所以我一直在尋找這個一個星期的時間,然後閱讀所有類似的問題,但都沒有像我一樣問完全相同的問題(嘗試反向工程其他類似於我的解決方案希望沒有成功如何在沒有監聽器的情況下獲得javafx媒體元數據

解釋穴居人的風格:。我試圖使用元數據來創建列表

  1. 我有一個多對話框打開,並選擇一個以上的MP3
  2. 我把文件中的一個ArrayList<File>
  3. I lo OP雖然增強的for循環和提取元數據使用媒體變量
  4. 的信息的元數據(如「藝術家」)的文件是什麼,我想在一個ArrayList保存例如

問題聽者只能方式增強循環結束後導致 ArrayList<String>具有什麼也沒有一個對象

這裏是一個示例:

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 

回答

3

的通過添加偵聽器來讀取媒體源元數據的其他方式是在mediaplayer .setOnReady()中提取該信息;這裏是java控制器類

公共類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()中有一個喚醒主線程的循環,因此循環是能夠移動到下一個項目

我承認這可能不是最好的解決方案,但歡迎任何誰有更好的方法如何從文件列表中讀取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

0

您可以使用下面的函數來檢索的元數據對於一個給定的媒體對象:

public static void initializeMetaData(Media media) { 
    final Ref<Boolean> ready = new Ref<>(false); 

    MediaPlayer mediaPlayer = new MediaPlayer(media); 
    mediaPlayer.setOnReady(() -> { 
     synchronized (ready) { 
      ready.set(false); 
      ready.notify(); 
     } 
    }); 

    synchronized (ready) { 
     if (!ready.get()) { 
      try { 
       ready.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

但是,不要從一個JavaFX線程中調用initializeMetaData,否則線程運行陷入僵持。

PS:真的很可笑,人們必須建立這樣的解決方法。我希望將來Media將提供一個完成這項工作的initialize()方法。

0

我對這個問題的解決辦法是這樣的:

public class MediaListener implements MapChangeListener<String, Object> 
{ 
    public String title = null; 
    public String artist = null; 
    public String album = null; 

    private final Consumer<MediaListener> handler; 
    private boolean handled = false; 

    public MediaListener(Consumer<MediaListener> handler) 
    { 
     this.handler = handler; 
    } 

    @Override 
    public void onChanged(MapChangeListener.Change<? extends String, ?> ch) 
    { 
     if (ch.wasAdded()) 
     { 
      String key = ch.getKey(); 
      switch (key) 
      { 
       case "title": 
        title = (String) ch.getValueAdded(); 
        break; 
       case "artist": 
        artist = (String) ch.getValueAdded(); 
        break; 
       case "album": 
        album = (String) ch.getValueAdded(); 
        break; 
      } 

      if (!handled && title != null && artist != null && album != null) 
      { 
       handler.accept(this); 
       handled = true; 
      } 
     } 
    } 
} 

它可能不是最好的方式,但它比創建每個文件的一個新的MediaPlayer的方式清潔。

實例:

Media media = Util.createMedia(path); 
media.getMetadata().addListener(new MediaListener((data) -> 
{ 
    // Use the data object to access the media 
})); 
相關問題