我想开发一个以特定方式播放 mp3 文件的 Java 程序。我用 startTime 和 endTime 标记了该文件中的多个片段。程序应播放第一个片段,然后休眠 5 秒钟。然后播放第二个片段并再次 sleep 。等等。我使用 JavaFX 类 MediaPlayer。程序原型(prototype)如下:
import javafx.application.Application;
import javafx.stage.Stage;
import java.io.FileNotFoundException;
import java.io.IOException;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import java.util.concurrent.TimeUnit;
public class JavaFXMediaPlayer02 extends Application {
@Override
public void start(Stage stage) throws FileNotFoundException,IOException,InterruptedException {
Media media = new Media("file:///D:/1016_00.mp3");
MediaPlayer mediaPlayer = new MediaPlayer(media);
//Set and play the first fragment of mp3-file
mediaPlayer.setStartTime(Duration.millis(1219.0));
mediaPlayer.setStopTime(Duration.millis(2728.0));
mediaPlayer.play();
System.out.println("1st fragment played!");
TimeUnit.SECONDS.sleep(5);
//Set and play the second fragment
mediaPlayer.setStartTime(Duration.millis(3947.0));
mediaPlayer.setStopTime(Duration.millis(6629.0));
mediaPlayer.play();
System.out.println("2nd fragment played!");
TimeUnit.SECONDS.sleep(5);
//Set and play the second fragment
mediaPlayer.setStartTime(Duration.millis(7453.0));
mediaPlayer.setStopTime(Duration.millis(10704.0));
mediaPlayer.play();
System.out.println("3rd fragment played!");
}
public static void main(String[] args) {
launch(args);
}
}
但我只听到了第三个片段。怎么了?为什么我听不到第一个和第二个片段?如何修正我的程序? JavaFX 不是适合我的任务的工具吗?
请您参考如下方法:
这里的问题在于 TimeUnit.SECONDS.sleep(5);
调用。该方法将当前线程设置为 sleep 状态。在您的情况下,该线程是 JavaFX 应用程序线程。这会导致整个应用程序“卡住”(如果添加一些 GUI 元素,情况会更明显),因此会执行 mediaPlayer.play();
命令,但会立即“卡住”,因为的 sleep 功能。在 `TimeUnit.SECONDS.sleep(5);
调用之后,您为 MediaPlayer
设置新的开始和结束时间并执行 play()
再次,以便轨道在新的开始时间开始。这就是为什么只播放最后一个片段。
现在解决方案: 您永远不应该在 JavaFX 应用程序线程上调用 Thread.sleep() 或类似方法。但就您而言,您必须在播放片段之间等待一定的时间。第一种方法是在新线程上调用 Thread.sleep() 或 TimeUnit.SECONDS.sleep(5); 并调用 Mediaplayer JFX 应用程序线程上的方法。但这无法正常工作,因为您尚未设置调用线程的“顺序”。有多种方法可以做到这一点(通过 Semaphores 、 Locks and Conditions 、 JavaFX Concurrency 等等...)
我试图通过一些快速而肮脏的编程来解决你的问题,但我遇到了 mediaPlayer.setStopTime(Duration.millis());
的问题。它似乎不适用于我的电脑,因此文件总是播放到最后。我添加了一个停止按钮来模拟自动停止。 以下类设置新的起点和终点并播放片段。如果媒体播放器停止,它将调用 LittleMediaScheduler
类上的下一个片段。
public class LittleMediaHelper implements Runnable {
public double startTime;
public double endTime;
public MediaPlayer player;
public int id;
public LittleMediaScheduler scheduler;
public LittleMediaHelper(double startTime, double endTime,
MediaPlayer player, int id) {
this.startTime = startTime;
this.endTime = endTime;
this.player = player;
this.id = id;
}
public LittleMediaScheduler getScheduler() {
return scheduler;
}
public void setScheduler(LittleMediaScheduler scheduler) {
this.scheduler = scheduler;
}
@Override
public void run() {
Platform.runLater(new Runnable() {
@Override
public void run() {
player.setStartTime(Duration.millis(startTime));
player.setStopTime(Duration.millis(endTime));
System.out.println(player.getStartTime());
System.out.println(player.getStopTime());
player.play();
player.setOnStopped(new Runnable() {
@Override
public void run() {
int idtmp = id + 1;
System.out.println("NEXT " + idtmp);
scheduler.call(idtmp);
}
});
}
});
}
}
此类负责在新线程上休眠一定时间,并在成功休眠后调用下一个 LittleMediaHelper
类播放功能。
public class LittleMediaScheduler {
private ArrayList<LittleMediaHelper> hArrL;
private int SLEEPTIME = 2000;
public LittleMediaScheduler(LittleMediaHelper... helpers) {
this.hArrL = new ArrayList<>();
for (LittleMediaHelper h : helpers) {
h.setScheduler(this);
System.out.println(h.startTime);
this.hArrL.add(h);
}
System.out.println(hArrL.size());
}
public void init() {
Thread t = new Thread(this.hArrL.get(0));
t.start();
}
public void call(final int id) {
Thread t = new Thread(new Task<String>() {
@Override
protected String call() throws Exception {
Thread.sleep(SLEEPTIME);
return null;
}
@Override
protected void succeeded() {
super.succeeded();
System.out.println("Next playing...");
if (id > LittleMediaScheduler.this.hArrL.size() - 1) {
return;
}
LittleMediaHelper next = LittleMediaScheduler.this.hArrL
.get(id);
Thread nextT = new Thread(next);
nextT.start();
}
});
t.start();
}
}
带有停止按钮的主类。如果没有 mediaPlayer.pause()
,尽管设置了新的开始结束端点,播放器仍会以某种方式重复一个步骤两次。不知道这是否是一个错误。
public class JavaFXMediaPlayer02 extends Application {
@Override
public void start(Stage stage) throws FileNotFoundException, IOException,
InterruptedException {
Media media = new Media("file:///C:/test.mp3");
final MediaPlayer mediaPlayer = new MediaPlayer(media);
LittleMediaHelper phase1 = new LittleMediaHelper(0, 1000, mediaPlayer,
0);
LittleMediaHelper phase2 = new LittleMediaHelper(50000, 55000,
mediaPlayer, 1);
LittleMediaHelper phase3 = new LittleMediaHelper(200000, 200500,
mediaPlayer, 2);
LittleMediaScheduler scheduler = new LittleMediaScheduler(phase1,
phase2, phase3);
scheduler.init();
Group g = new Group();
Button b = new Button("STOP");
b.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
mediaPlayer.pause();
mediaPlayer.stop();
}
});
g.getChildren().add(b);
Scene sc = new Scene(g);
stage.setScene(sc);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}