3 Replies Latest reply: Jan 25, 2013 8:30 AM by MiPa RSS

    Why can't I delete a media file after stopping the JavaFX media player?

    mambha
      In my first attempt at using the JavaFX 2 media player, I noticed that attempting to delete the file associated with the media (after the media player has been stopped) results in a failure. My attempt happened to be using JRE 1.7.0_10 with JavaFx 2.2.4-b18 on a 64-bit Windows machine.

      In particular, calling Files.deleteIfExists() on the path of the media file for which the media player has been stopped, results in IOException with the message 'The process cannot access the file because it is being used by another process'.

      I am attaching sample code (loosely based on a textbook example) with which I was able to replicate this condition. This application is meant to play a media file that is dragged to it (assuming the JavaFX 2 media player is capable of playing it). If another media file is dragged later, the previous is stopped from playing, and an attempt is made to delete the previous file. It is this attempt that fails. (If you try this, please use media files you can afford to delete, just in case the code works as desired.)

      In poring over the Media and MediaPlayer APIs, I did not notice any 'cleanup' API that might be necessary to make this work. Am I missing something basic?

      I noticed this behavior in my Swing application, into which I added a JavaFX media player (in my first ever attempt at using JavaFX). That particular application uses some temporary media files, which it is required to delete under some conditions. And I only get the error on the last media file played. I am currently working around my issue by calling deleteOnExit() on any file that suffers the above IOException. And even for that to work, I have to ensure I first call Platform.exit() when the Swing application exits.

      It would appear that JavaFX media player is not cleaning up resources after stopping. But I stand to be corrected.

      And now the code for the sample JavaFX application (no Swing); notice the println() calls, especially the one saying "Failed to delete file":
      public class PlayMediaAndDelete extends Application {
          private MediaPlayer mediaPlayer;
          private File previousFile;
          private File currentFile;
      
          public static void main(String[] args) {
              Application.launch(args);
          }
      
          @Override
          public void start(final Stage primaryStage) {
              primaryStage.setTitle("Play Media File and Delete Media File");
              primaryStage.centerOnScreen();
              primaryStage.initStyle(StageStyle.TRANSPARENT);
              
              Group root = new Group();
              Scene scene = new Scene(root, 250, 150, Color.rgb(0, 0, 0, 0));
              
              Rectangle applicationArea = RectangleBuilder.create().build();
              root.getChildren().add(applicationArea);
              applicationArea.widthProperty().bind(scene.widthProperty());
              applicationArea.heightProperty().bind(scene.heightProperty());
              
              final Group phaseNodes = new Group();        
              root.getChildren().add(phaseNodes);
                      
              scene.setOnDragOver(new EventHandler<DragEvent>() {
                  @Override
                  public void handle(DragEvent event) {
                      Dragboard db = event.getDragboard();
                      if (db.hasFiles()) {
                          event.acceptTransferModes(TransferMode.COPY);
                      } else {
                          event.consume();
                      }
                  }
              });
              
              scene.setOnDragDropped(new EventHandler<DragEvent>() {
                  @Override
                  public void handle(DragEvent event) {
                      Dragboard db = event.getDragboard();
                      boolean success = false;
                      if (db.hasFiles()) {
                          success = true;
                          String filePath = null;
                          for (File file:db.getFiles()) {
                              filePath = file.getAbsolutePath();
                              System.out.println("File dragged " + filePath);
                          }
                          previousFile = currentFile;
                          currentFile = new File(filePath);
                          Media media = new Media(currentFile.toURI().toString());
      
                          // stop previous media's player and delete the associated media file
                          if (mediaPlayer != null) {
                              System.out.println("Stopping media player for " + previousFile);
                              mediaPlayer.stop();
                              try {
                                  Files.deleteIfExists(previousFile.toPath());
                              } catch (IOException e) {
                                  System.err.println("Failed to delete file " + previousFile + ": " + e.getMessage());
                              }
                          }
      
                          mediaPlayer = MediaPlayerBuilder.create().media(media).build();
      
                          mediaPlayer.setOnReady(new Runnable() {
                              @Override
                              public void run() {
                                  System.out.println("Playing " + mediaPlayer.getMedia().getSource());
                                  mediaPlayer.play();
                              }
                          }); 
                      }
                      
                      event.setDropCompleted(success);
                      event.consume();
                  }
              });
      
              // close button
              final Group closeApp = new Group();
              Node closeButton = CircleBuilder.create()
                      .centerX(5)
                      .centerY(0)
                      .radius(7)
                      .fill(Color.rgb(255, 255, 255, .80))
                      .build();
              Node closeText = new Text(2, 4, "X");
              closeApp.translateXProperty().bind(scene.widthProperty().subtract(15));
              closeApp.setTranslateY(10);
              closeApp.getChildren().addAll(closeButton, closeText);
              closeApp.setOnMouseClicked(new EventHandler<MouseEvent>() {
                  @Override
                  public void handle(MouseEvent event) {
                      Platform.exit();
                  }
              });
              
              root.getChildren().add(closeApp);
              
              primaryStage.setScene(scene);
              primaryStage.show();
          }
      }