How to go to Next Screen only when the Background thread is completed in javaFx - javafx-2

I have the first scene in which I have a registration button on click of the button I try to establish a connection to my server in a background thread. Now I want to go to next scene only when I gets 200 as response code from my server.
I have used Service class for background thread.I have also created a method to change the scene but I am not able to understand where and when to call mehod.
public class MainController implements Initializable {
int responseCodeFromServer;;
// creating background thread
private Service<Void>backgroundThread;
backgroundThread = new Service<Void>()
{
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception
{
// Now here we will try to establish the connection with the Server
EstablishServerConnection obj = new EstablishServerConnection();
responseCodeFromServer = obj.establishConnectionToServer(registrationBeanObj);
System.out.println("Response Code received in UI thread "+ responseCodeFromServer);
if(responseCodeFromServer == 200)
{
updateMessage("All Ok");
// now when we get response code as 200 then we need to take the user to the next window
}
else
{
updateMessage("Server Issue");
}
// TODO Auto-generated method stub
return null;
}
};
}
};
// we will define here what will happen when this background thread completes its job successfully (we can also try for failed or cancelled events)
backgroundThread.setOnSucceeded(new EventHandler<WorkerStateEvent>()
{
#Override
public void handle(WorkerStateEvent event) {
// TODO Auto-generated method stub
if(responseCodeFromServer == 200)
{
System.out.println("Done");
}
// It is a good idea to unbind the label when our background task is finished
status.textProperty().unbind();
}
});
// we need to bind status label text property to the message property in our background thread
status.textProperty().bind(backgroundThread.messageProperty());
// we need to start our background thread
backgroundThread.restart();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
System.out.println("Hello World");
}
public void goToProductKey(ActionEvent event) throws IOException
{
Parent goToProductKeyParent = FXMLLoader.load(getClass().getResource("ProductKeyFXML.fxml"));
Scene goToProductKeyScene = new Scene(goToProductKeyParent);
// This line gets the stage Information
Stage window = (Stage)((Node)event.getSource()).getScene().getWindow();
window.setScene(goToProductKeyScene);
window.show();
}
My Question is I want to go to next scene only when i get 200 as response code from my server.I am new to JavaFX

backgroundThread.setOnSucceeded(new EventHandler<WorkerStateEvent>()
{
#Override
public void handle(WorkerStateEvent event)
{
// TODO Auto-generated method stub
if(responseCodeFromServer == 1)
{
Parent goToProductKeyParent = null;
try {
goToProductKeyParent = FXMLLoader.load(getClass().getResource("ProductKeyFXML.fxml"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Scene goToProductKeyScene = new Scene(goToProductKeyParent);
// This line gets the stage Information
Stage window = (Stage) rootPane.getScene().getWindow();
//Stage window = (Stage)((Node)event.getSource()).getScene().getWindow();
window.setScene(goToProductKeyScene);
window.show();
}
// It is a good idea to unbind the label when our background task is finished
status.textProperty().unbind();
}
});
// we need to bind status label text property to the message property in our background thread
status.textProperty().bind(backgroundThread.messageProperty());
// we need to start our background thread
backgroundThread.start();

Related

Platform.runLater() method

I'm trying to understand, whether Platform.runLater() method invokes just the SAME JavaFxApplicationThread, as in start()-method or ANOTHER, PARALLEL thread with the same name?
In the code below:
1) first, start()-method was invoked with JavaFxApplicationThread;
2) then, startFilling()-method was invoked, where new thread starts;
3) at last, new Stage was opened with method openMessage(), where Platform.runLater() method was used.
Please see the code:
public class FillingTimeLine extends Application {
private LongProperty lp = new SimpleLongProperty(0);
private Timeline timeline = new Timeline();
#Override
public void start(Stage primaryStage) throws Exception {
// TODO Auto-generated method stub
System.out.println("\nSTARTING THREAD: " + Thread.currentThread().getName());
StackPane spane = new StackPane();
ProgressBar pb = new ProgressBar(0);
pb.setMinSize(160, 21.5);
pb.setMaxSize(160, 21.5);
pb.setPrefSize(160, 21.5);
pb.progressProperty().bind(lp.divide(10000 * 1.0));
pb.setStyle("-fx-base:darkgray;-fx-accent:red;");
spane.getChildren().add(pb);
Scene scene = new Scene(spane, 300, 300);
primaryStage.setScene(scene);
primaryStage.show();
startFilling();
openNewStage();
}
public void startFilling() throws InterruptedException {
new Thread(() -> {
System.out.println("\nSTARTING THREAD: " + Thread.currentThread().getName());
timeline = new Timeline(new KeyFrame(Duration.seconds(0), new KeyValue(lp, 0)),
new KeyFrame(Duration.seconds(20), new KeyValue(lp, 20000)));
if (Thread.currentThread().isInterrupted()) {
System.out.println("\n THR WAS INTERRUPTED!");
return;
}
timeline.play();
try {
Thread.sleep(20000);
} catch (InterruptedException ex) {
System.out.println("\n THR WAS INTERRUPTED!");
return;
}
}).start();
}
public void stopFilling() {
new Thread(() -> {
System.out.println("\nSTOPPING THREAD: " + Thread.currentThread().getName());
timeline.stop();
}).start();
}
public void openNewStage() {
Platform.runLater(() -> {
System.out.println("\nOPENNING THREAD" + Thread.currentThread().getName());
Stage qst = new Stage();
StackPane sp = new StackPane();
Button btn = new Button("STOP");
btn.setMaxHeight(25);
btn.setMinHeight(25);
btn.setPrefHeight(25);
btn.setMaxWidth(80);
btn.setMinWidth(80);
btn.setPrefWidth(80);
btn.setAlignment(Pos.CENTER);
btn.setOnAction(e -> {
try {
qst.close();
stopFilling();
} catch (Exception e1) {
return;
}
});
sp.getChildren().add(btn);
Scene scene = new Scene(sp, 200, 120);
qst.setX(50);
qst.setY(50);
qst.setScene(scene);
qst.setResizable(false);
qst.show();
});
}
public static void main(String[] args) {
launch(args);
}
}
I thougt Platform.runLater() enables parallel execution. And I expected, that new Stage with a STOP-button would be opened by another thread, because JavaFxApplicationThread was still busy with primaryStage.
But CONSOLE PUTPUT shows that new Stage was opened also with JavaFxApplicationThread- just as primaryStage:
STARTING THREAD: JavaFX Application Thread
STARTING THREAD: Thread-3
OPENNING THREAD: JavaFX Application Thread
STOPPING THREAD: Thread-4
So how can one and the same thread open new Stage, if primaryStage is still showing and is not closed?
Or is OPENING THREAD - another, parallel thread with the same name?
Thank you in advance

JavaFX - Cancel Task doesn't work

In a JavaFX application, I have a method which takes a long time on large input. I'm opening a dialog when it is loading and I'd like the user to be able to cancel/close out the dialog and the task will quit. I created a task and added its cancellation in the cancel button handling. But the cancellation doesn't happen, the task doesn't stop executing.
Task<Void> task = new Task<Void>() {
#Override
public Void call() throws Exception {
// calling a function that does heavy calculations in another class
};
task.setOnSucceeded(e -> {
startButton.setDisable(false);
});
}
new Thread(task).start();
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
System.out.println("Button handled");
task.cancel();
}
);
Why isn't the task getting canceled when the button clicked?
You have to check on the cancel state (see Task's Javadoc). Have a look at this MCVE:
public class Example extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
new AnotherClass().doHeavyCalculations(this);
return null;
}
};
Button start = new Button("Start");
start.setOnMouseClicked(event -> new Thread(task).start());
Button cancel = new Button("Cancel");
cancel.setOnMouseClicked(event -> task.cancel());
primaryStage.setScene(new Scene(new HBox(start, cancel)));
primaryStage.show();
}
private class AnotherClass {
public void doHeavyCalculations(Task<Void> task) {
while (true) {
if (task.isCancelled()) {
System.out.println("Canceling...");
break;
} else {
System.out.println("Working...");
}
}
}
}
}
Note that…
You should use Task#updateMessage(String) rather than printing to System.out, here it's just for demonstration.
Directly injecting the Task object creates a cyclic dependency. However, you can use a proxy or something else that fits your situation.

JavaFX application UI responsive

Sorry for poor English. I am new in JavaFX. I am writing a JavaFX application with COM port. I send AT command and get response from COM port then initialize some variable. In this controller have 3 method by which initialize 3 variable.
private void findModemPorts() {
// send 4 AT command then
// get response & initialize myPort
myPort = "XXXX";
}
private void findNumber() {
// send 4 AT command then
// get response & initialize myNumber
myNumber= "XXXX";
}
private void currentBalanc() {
// send 10 AT command then
// get response & initialize currentBalance
currentBalance ="XXXX";
}
now call this 3 method in a buttonAction event
#FXML
private void handleStartButtonAction(ActionEvent event) {
pin = text_field_pin.getText();
backgroundThread = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
findModemPorts();
findModemPorts();
currentBalanc();
return null;
}
};
}
};
backgroundThread.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
level_oparetor.setText(myOparetor);
level_number.setText(myNumber);
level_current_balance.setText(currentBalance);
}
});
backgroundThread.start();
}
when run this application complete the full task abut 30 second then 3 level set text in at a time after Succeeded. But I want set text every level after initialize one by one vale. Please help me. thanks in advance.
You can either do what #Dvarga said or you can just make use of Platform.runLater which runs your code on the JavaFX application thread.
#Override
protected Void call() throws Exception {
findModemPorts();
Platform.runLater(() -> level_oparetor.setText(myOparetor));
findModemPorts();
Platform.runLater(() -> level_number.setText(myNumber));
currentBalanc();
Platform.runLater(() -> level_current_balance.setText(currentBalance));
return null;
}
Call the three method in three different tasks with three different OnSucceed handler, therefore the three update will be independent from each other.

Replace a TableView with a ProgressIndicator within VBox JavaFX

I have a TableView associated with some data, and once i hit a run button i perform some processing on that data. Each row of data is handled in a seperate thread, and while those threads are running i want a ProgressInducator to replace the table within its vbox.
In the attached code:
If I stop where is says "WORKS IF STOP HERE" - table is replaced with pi.
If I continue waiting for the threads to join - no replacing.
What am I missing?
runButton.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(final ActionEvent e) {
List<Thread> threadList = new ArrayList<Thread>();
int threadCounter = 0;
final ProgressIndicator pi = new ProgressIndicator(threadCounter);
vbox.getChildren().clear();
vbox.getChildren().addAll(pi);
for (ProductInTable product : data) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try
{
product.calculate();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
});
threadList.add(thread);
thread.start();
}
int x = threadList.size();
/** WORKS IF STOP HERE **/
// wait for all threads to end
for (Thread t : threadList) {
try {
t.join();
threadCounter++;
pi.setProgress(threadCounter / x);
} catch (InterruptedException interE) {
interE.printStackTrace();
}
}
/** DOESNT WORKS IF STOP HERE **/
Thread.join() blocks execution until the thread is completed. Since you are calling this on the FX Application Thread, you block that thread until all your worker threads finish. This means the UI is unable to update until those threads are complete.
A better approach is probably to represent each computation with a task, and update a counter of complete tasks back on the FX Application Thread using setOnSucceeded. Something like:
runButton.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(final ActionEvent e) {
final ProgressIndicator pi = new ProgressIndicator(threadCounter);
vbox.getChildren().clear();
vbox.getChildren().addAll(pi);
final int numTasks = data.size();
// only access from FX Application thread:
final IntegerProperty completedTaskCount = new SimpleIntegerProperty(0);
pi.progressProperty().bind(completedTaskCount.divide(1.0*numTasks));
completedTaskCount.addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> obs, Number oldValue, Number newValue) {
if (newValue.intValue() >= numTasks) {
// hide progress indicator and show table..
}
}
});
for (final ProductInTable product : data) {
Task<Void> task = new Task<Void>() {
#Override
public Void call() {
try
{
product.calculate();
} catch (IOException ioe) {
ioe.printStackTrace();
}
return null ;
}
});
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
completedTaskCount.set(completedTaskCount.get()+1);
}
});
new Thread(task).start();
}
}
});
If you potentially have a large number of items here, you should use some kind of ExecutorService instead to avoid creating too many threads:
ExecutorService exec = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors()); // for example...
and then replace
new Thread(task).start();
with
exec.submit(task);

Android MediaPlayer seek bar current position thread issues

Hi I am new to android and I am learning by example. I am trying to make an activity that has a list view of all songs in my raw folder with media player controls at the bottom. I have everything working so far but I can't seem to get the SeekBar to stop force closing.
Here is the code:
public class music extends ListActivity implements Runnable {
private ArrayList<sound> mSounds = null;
private soundadapter mAdapter = null;
private ImageButton playbtn;
private SeekBar seekbar;
private int total;
private MediaPlayer mp = null;
private TextView selelctedFile = null;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.music);
selelctedFile = (TextView) findViewById(R.id.selectedfile);
seekbar = (SeekBar) findViewById(R.id.seekbar);
seekbar.setProgress(0);
// create a simple list
mSounds = new ArrayList<sound>();
sound s = new sound();
s.setDescription("Rudolph The Red Nosed Reindeer");
s.setSoundResourceId(R.raw.rudolphtherednosereindeer);
mSounds.add(s);
s = new sound();
s.setDescription("Battery");
s.setSoundResourceId(R.raw.battery);
mSounds.add(s);
mAdapter = new soundadapter(this, R.layout.listitem, mSounds);
setListAdapter(mAdapter);
playbtn = (ImageButton) findViewById(R.id.play);
playbtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
try {
if (mp.isPlaying()) {
mp.pause();
playbtn.setImageResource(android.R.drawable.ic_media_play);
} else {
mp.start();
playbtn.setImageResource(android.R.drawable.ic_media_pause);
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
}
});
}
#Override
public void onListItemClick(ListView parent, View v, int position, long id) {
sound s = (sound) mSounds.get(position);
if (mp != null) {
mp.reset();
mp.release();
}
mp = MediaPlayer.create(this, s.getSoundResourceId());
selelctedFile.setText(s.getDescription());
playbtn.setImageResource(android.R.drawable.ic_media_pause);
mp.start();
total = mp.getDuration();
seekbar.setMax(total);
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekbar) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekbar) {
// TODO Auto-generated method stub
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
if (fromUser) {
mp.seekTo(progress);
seekBar.setProgress(progress);
}
}
});
Thread currentThread = new Thread(this);
currentThread.start();
}
#Override
public void run() {
// TODO Auto-generated method stub
try {
while (mp != null) {
int currentPosition = mp.getCurrentPosition();
Message msg = new Message();
msg.what = currentPosition;
threadHandler.sendMessage(msg);
Thread.sleep(100);
}
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
}
}
private Handler threadHandler = new Handler() {
public void handleMessage(Message msg) {
// super.handleMessage(msg);
// txt.setText(Integer.toString(msg.what));
seekbar.setProgress(msg.what);
}
};
#Override
protected void onPause() {
// TODO Auto-generated method stub
mp.stop();
mp.release();
mp = null;
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
if(mp != null) {
mp.stop();
mp.release();
mp = null;
}
}
}
and here is the error i keep getting when i click several times on different songs:
04-14 02:53:00.452: W/dalvikvm(27452): threadid=19: thread exiting with uncaught exception (group=0x40018560)
04-14 02:53:00.466: E/AndroidRuntime(27452): FATAL EXCEPTION: Thread-22
04-14 02:53:00.466: E/AndroidRuntime(27452): java.lang.IllegalStateException
04-14 02:53:00.466: E/AndroidRuntime(27452): at android.media.MediaPlayer.getCurrentPosition(Native Method)
04-14 02:53:00.466: E/AndroidRuntime(27452): at net.cybercore.collapsingfromwithin.music.run(music.java:145)
04-14 02:53:00.466: E/AndroidRuntime(27452): at java.lang.Thread.run(Thread.java:1019)
Line error 145 is :
int currentPosition = mp.getCurrentPosition();
I cannot for the life of me figure out why it works for 3 or 4 times playing and then it kills the app.
Any help is appreciated. I have already looked at several other sites for examples including http://www.androidhive.info/2012/03/android-building-audio-player-tutorial/ and http://www.androiddevblog.net/android/playing-audio-in-android
**
UPDATE
**
I think I fixed it. thanks for your help I found Thread using for seekbar on android mediaplayer so i changed it to
#Override
public void run() {
// TODO Auto-generated method stub
try {
while (mp != null) {
int currentPosition = mp.getCurrentPosition();
Message msg = new Message();
msg.what = currentPosition;
threadHandler.sendMessage(msg);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("interrupt exeption" + e);
}
}
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("My exeption" + e);
}
}
I still get the errors but they are not killing my app. I don't think this is right way to do it but its working.
You should prepare your media player when instanciating it.
A MediaPlayer object must first enter the Prepared state before playback can be started.
There are two ways (synchronous vs. asynchronous) that the Prepared state can be reached: either a call to prepare() (synchronous) which transfers the object to the Prepared state once the method call returns, or a call to prepareAsync() (asynchronous) which first transfers the object to the Preparing state after the call returns (which occurs almost right way) while the internal player engine continues working on the rest of preparation work until the preparation work completes. When the preparation completes or when prepare() call returns, the internal player engine then calls a user supplied callback method, onPrepared() of the OnPreparedListener interface, if an OnPreparedListener is registered beforehand via setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener).
Read it here
so you should call mp.prepare() after instanciating the player.
also you should make sure the media player in playing to run the run method. I'd start by adding
mp.isPlaying() to the while line.
while (mp != null && mp.isPlaying()) {
...
}
IllegalStateException means that you are on an illegal state to call that method, like for instance, if the player is stopped.
I'm not sure, but I think this will stop the run method when you pause the music. So you should try to avoid this. I create a boolean to identify that the player is playing or paused and use it on the while.

Resources