I wanted to test my App on my phone, so I send it to the Build server (Android). Instead of the expected, successfull build, I got an error:
Error! Failed to transform some classes
java.lang.RuntimeException: java.lang.ClassNotFoundException: com.private.container.projectDetailsContainer.top.center.progCircle.ProgressCircle
at net.orfjackal.retrolambda.lambdas.BackportLambdaInvocations.loadClass(BackportLambdaInvocations.java:116)
at net.orfjackal.retrolambda.lambdas.BackportLambdaInvocations.access$100(BackportLambdaInvocations.java:16)
at net.orfjackal.retrolambda.lambdas.BackportLambdaInvocations$InvokeDynamicInsnConverter.backportLambda(BackportLambdaInvocations.java:101)
at net.orfjackal.retrolambda.lambdas.BackportLambdaInvocations$InvokeDynamicInsnConverter.visitInvokeDynamicInsn(BackportLambdaInvocations.java:94)
at net.orfjackal.retrolambda.asm.ClassReader.readCode(ClassReader.java:1452)
at net.orfjackal.retrolambda.asm.ClassReader.readMethod(ClassReader.java:1017)
at net.orfjackal.retrolambda.asm.ClassReader.accept(ClassReader.java:693)
at net.orfjackal.retrolambda.asm.ClassReader.accept(ClassReader.java:506)
at net.orfjackal.retrolambda.Transformers.lambda$transform$4(Transformers.java:106)
at net.orfjackal.retrolambda.Transformers$$Lambda$8/636718812.accept(Unknown Source)
at net.orfjackal.retrolambda.Transformers.transform(Transformers.java:120)
at net.orfjackal.retrolambda.Transformers.transform(Transformers.java:106)
at net.orfjackal.retrolambda.Transformers.backportClass(Transformers.java:46)
at net.orfjackal.retrolambda.Retrolambda.run(Retrolambda.java:72)
at net.orfjackal.retrolambda.Main.main(Main.java:26)
Caused by: java.lang.ClassNotFoundException: com.private.container.projectDetailsContainer.top.center.progCircle.ProgressCircle
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at net.orfjackal.retrolambda.NonDelegatingClassLoader.loadClass(NonDelegatingClassLoader.java:27)
at net.orfjackal.retrolambda.lambdas.BackportLambdaInvocations.loadClass(BackportLambdaInvocations.java:114)
... 14 more
What am I doing wrong?
Notice
I already used the App on my mobile device and there was no problem with it
The App has no problems running in the simulator
EDIT 1
As you asked for it, here is the way I use the class (the only time I use it):
package com.companyname.mobile.container.projectDetailsContainer.top.center.progCircle;
import java.util.HashMap;
import com.codename1.ui.Container;
import com.codename1.ui.Label;
import com.codename1.ui.layouts.BorderLayout;
import com.codename1.ui.layouts.BoxLayout;
import com.codename1.ui.layouts.GridLayout;
import com.companyname.mobile.renderer.projectListitem.ProjectListItem;
public class ProgressCircleContainer extends Container {
/* attributes */
private ProgressCircle progressCircle;
/************************/
/**
* Constructor for the Container.
* The given parameter is the clicked listitem
*
* #param clicked List item clicked by the user
*/
public ProgressCircleContainer (ProjectListItem clicked) {
this.clicked = clicked;
init();
}
/*
* initializes the layout of the container
*/
private void init () {
this.layout = new GridLayout (2);
/* left container */
progressCircle = new ProgressCircle(clicked.getStatus());
leftCont = new Container ();
leftContLayout = new BorderLayout();
leftCont.setLayout(leftContLayout);
leftCont.add(BorderLayout.CENTER, progressCircle);
/****************************/
this.add(leftCont); //using gridlayout for the form
}
/* Getter and Setter */
}
The class is much larger, but I left out the unnessecary parts of it.
Here is the ProgCircle class:
package com.companyname.mobile.container.projectDetailsContainer.top.center.progCircle;
import java.io.IOException;
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.Graphics;
import com.codename1.ui.Image;
import com.codename1.ui.Label;
import com.codename1.ui.layouts.FlowLayout;
import com.codename1.ui.layouts.LayeredLayout;
import com.codename1.ui.util.Resources;
import com.codename1.ui.Graphics;
import com.codename1.ui.geom.Rectangle;
/**
* This class partly draws and partly displays the round progress circle
* one can see in the north of ProjectDetailsForm.
*
* It uses a LayeredLayout to paint the progress as a circle in the background
* while concealing the unnecessary part of it with a picture. On the GlassPane
* layer, there is a label showing the progress in percent
*
* {#http://stackoverflow.com/questions/35841377/how-to-make-a-round-progress-bar-in-codename-one}
*
*/
public class ProgressCircle extends Container {
/* attributes */
private Label percent;
private LayeredLayout layout;
/************************/
/* constants */
public static final String ROUND_PROG_BAR = "roundprogbar.png";
/************************/
/**
* Constructor for the round progress bar.
* The parameter given is the color it will be drawn in.
*
* #param statusColor color the progress will be drawn in
*/
public ProgressCircle (int statusColor) {
layout = new LayeredLayout();
this.setLayout(layout);
try {
Resources s = Resources.open("/theme.res");
Image progressOverlayImage = s.getImage(ROUND_PROG_BAR);
int currentProgress360 = 100;
percent = new Label (String.valueOf((int) (((double)currentProgress360 /360)*100))+ "%");
percent.getUnselectedStyle().setFgColor(0x000000);
percent.getUnselectedStyle().setAlignment(Component.CENTER);
this.add(new Label (progressOverlayImage.scaled((int)(progressOverlayImage.getWidth()*0.65), (int)(progressOverlayImage.getHeight()*0.65)), "Container")).
add(FlowLayout.encloseCenterMiddle(percent));
this.getUnselectedStyle().setBgPainter((Graphics g, Rectangle rect) -> {
g.setColor(statusColor);
g.fillArc(this.getX(), this.getY(),(int)(progressOverlayImage.getWidth()*0.65), (int)(progressOverlayImage.getHeight()*0.65), 0, currentProgress360);
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
Another notice:
I was wondering if it could be the too long package name. I replaced my companies name by 'companyname', but their length is equal.
If you need further information, let me know.
If it does not compile like this, I may have deleted a nessecary part, but then it is my fault right now. The app compiles successfully in the simulator and is fully functioning
EDIT 2:
here a link to the full error:
http://pastebin.com/ktCAbxk5
Have you modified your project class path in any way (eg added any jars or other source dirs)?
Do you have a class within the package com.private?
private is a reserved word in Java so I'm actually very surprised this works for you anywhere.
Related
When using the toolbar search feature, I encounter two issues.
The first (esthetical) problem is that when entering or leaving the search mode, the toolbar disappears for a moment, resulting in a flicker on the screen.
The second (functional) problem is that together with a side menu, the pointer dragged event results in a NullPointerException in the actionPerformed method on line 1302 of Toolbar.java. As a result, no scrolling is possible while in search mode.
Both problems can be replicated in the simulator and on Android using the form below.
Kind regards, Frans.
import com.codename1.ui.FontImage;
import com.codename1.ui.Form;
import com.codename1.ui.TextArea;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.layouts.BorderLayout;
public class ToolbarSearchForm extends Form
{
public ToolbarSearchForm()
{
super("Toolbar search", new BorderLayout());
getToolbar().addSearchCommand(e -> filter((String)e.getSource()));
getToolbar().addMaterialCommandToSideMenu("Settings", FontImage.MATERIAL_SETTINGS, this::settingsAction);
TextArea text = new TextArea(100, 100);
text.getAllStyles().setFgColor(0xFF000000);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++)
{
sb.append(i + " Hello World!\n");
}
text.setText(sb.toString());
add(BorderLayout.CENTER, text);
}
private void filter(String filter)
{
System.out.println(filter);
}
private void settingsAction(ActionEvent e)
{
System.out.println(e);
}
}
The complete stack trace is:
java.lang.NullPointerException
at com.codename1.ui.Toolbar$4.actionPerformed(Toolbar.java:1302)
at com.codename1.ui.util.EventDispatcher.fireActionSync(EventDispatcher.java:459)
at com.codename1.ui.util.EventDispatcher.fireActionEvent(EventDispatcher.java:362)
at com.codename1.ui.Form.pointerDragged(Form.java:3146)
at com.codename1.ui.Display.handleEvent(Display.java:2118)
at com.codename1.ui.Display.edtLoopImpl(Display.java:1051)
at com.codename1.ui.Display.mainEDTLoop(Display.java:969)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
java.lang.NullPointerException
at com.codename1.ui.Toolbar$4.actionPerformed(Toolbar.java:1302)
at com.codename1.ui.util.EventDispatcher.fireActionSync(EventDispatcher.java:459)
at com.codename1.ui.util.EventDispatcher.fireActionEvent(EventDispatcher.java:362)
at com.codename1.ui.Form.pointerDragged(Form.java:3146)
at com.codename1.ui.Display.handleEvent(Display.java:2118)
at com.codename1.ui.Display.edtLoopImpl(Display.java:1051)
at com.codename1.ui.Display.flushEdt(Display.java:826)
at com.codename1.ui.Form.showModal(Form.java:2098)
at com.codename1.ui.Dialog.showModal(Dialog.java:1137)
at com.codename1.ui.Dialog.show(Dialog.java:582)
at com.codename1.ui.Dialog.showPackedImpl(Dialog.java:1433)
at com.codename1.ui.Dialog.showPacked(Dialog.java:1349)
at com.codename1.ui.Dialog.showImpl(Dialog.java:1093)
at com.codename1.ui.Dialog.show(Dialog.java:1071)
at com.codename1.ui.Dialog.show(Dialog.java:1027)
at com.codename1.ui.Dialog.show(Dialog.java:793)
at com.codename1.ui.Dialog.show(Dialog.java:746)
at com.codename1.ui.Dialog.show(Dialog.java:711)
at com.codename1.ui.Dialog.show(Dialog.java:652)
at com.codename1.ui.Dialog.show(Dialog.java:807)
at com.codename1.ui.Display.mainEDTLoop(Display.java:982)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
The getComponentForm() returns null (because the toolbar has no parent) in this line of Toolbar.java: if (Display.getInstance().getImplementation().isScrollWheeling() || !enableSideMenuSwipe || getComponentForm().findCurrentlyEditingComponent() != null || getComponentForm().isEditing()) {
I added a workaround for this issue in this git commit. It should be in the update tomorrow.
This question is relative to the CN1Lib for Google Map.
My problem is that the the method addMarker(com.codename1.ui.Component marker, com.codename1.maps.Coord location) doesn't work as expected on my Android 7 real device if I don't use together the method setCameraPosition(com.codename1.maps.Coord crd).
To be more clear, with the following code I extend the class MapContainer: the problem is that I cannot remove the line this.setCameraPosition(coordinate); without breaking the functionality (if I remove that line, then I cannot add the marker to the tapped position).
I'm not sure if there is a bug in my code or in the CN1Lib.
public class MyMapContainer extends MapContainer {
private Label pin;
private Location markerLocation = new Location(0.0, 0.0);
MapObject mapObject = null;
/**
* Constructor that creates a default pinVector to be used with
* addMarker(Coord coordinate)
*/
public MyMapContainer() {
super();
Style s = new Style();
s.setFgColor(ColorUtil.BLACK);
pin = new Label(FontImage.createMaterial(FontImage.MATERIAL_PLACE, s, 10));
}
/**
* Constructor
*
* #param pinVector to be used with addMarker(Coord coordinate)
*/
public MyMapContainer(Image pinVector) {
this();
if (pinVector != null) {
pin = new Label(pinVector);
}
}
/**
* Adds a single marker (removes the previous one, if any)
*
* #param coordinate
*/
public void addMarker(Coord coordinate) {
if (mapObject != null) {
pin.remove();
this.removeMapObject(mapObject);
Log.p("Marker removed");
}
mapObject = this.addMarker(pin, coordinate);
this.setCameraPosition(coordinate);
Log.p("Marker added to the coordinate: " + coordinate.toString());
markerLocation.setLatitude(coordinate.getLatitude());
markerLocation.setLongitude(coordinate.getLongitude());
}
/**
* Returns the marker location
*
* #return markerLocation
*/
public Location getMarkerLocation() {
return markerLocation;
}
}
To test that extended class, I wrote this code in the main class:
mapContainer.addMarker(initialCoordinate);
mapContainer.zoom(initialCoordinate, 18);
mapContainer.addTapListener(e -> {
Coord userTappedCoord = mapContainer.getCoordAtPosition(e.getX(), e.getY());
Log.p("userTappedCoord: " + userTappedCoord);
mapContainer.addMarker(userTappedCoord);
});
--- UPDATE (as reply to the Shai's comment)
If I replace this.setCameraPosition with the following lines...
this.revalidate();
if (Display.getInstance().getCurrent() != null) {
Display.getInstance().getCurrent().revalidate();
}
//this.setCameraPosition(coordinate);
... the issue is the same: I cannot add a new marker. To be more clear, please see this video:
https://www.informatica-libera.net/VID_20180507_113028.mp4
In the video, the white circle corresponds to the point where I tap the screen. I tap it three times (you can hear the mouse clicks in the video), but the marker goes to a random position after each tapping, then it returns to the first position. This video is registered in a device farm, however I have the same identical issue with my real device.
I'm guessing that this is the problem:
pin.remove();
removeMapObject(mapObject);
One of them isn't working correctly so the pin retains its location. Try doing this instead:
removeMapObject(mapObject);
pin.remove();
If it doesn't work check the thesis by creating a new component instance instead of adding the same component over again. Assuming that solves the problem please file an issue with those details here.
I have added paypal android SDK under native/android package.Created native interface in main project structure(com.mycompany.myapp).Under native/android the implemented class is using the paypal sdk classes.
My implemented class:
package com.mycompany.myapp;
import com.paypal.android.sdk.payments.PayPalConfiguration;
import com.paypal.android.sdk.payments.PayPalPayment;
import com.paypal.android.sdk.payments.PaymentActivity;
import android.content.Intent;
import android.net.Uri;
import android.app.Activity;
import com.codename1.impl.android.AndroidNativeUtil;
import com.codename1.impl.android.CodenameOneActivity;
import java.math.BigDecimal;
public class MyNativeImpl {
// private static final String TAG = "paymentdemoblog";
/**
* - Set to PaymentActivity.ENVIRONMENT_PRODUCTION to move real money.
*
* - Set to PaymentActivity.ENVIRONMENT_SANDBOX to use your test credentials
* from https://developer.paypal.com
*
* - Set to PayPalConfiguration.ENVIRONMENT_NO_NETWORK to kick the tires
* without communicating to PayPal's servers.
*/
// private static final String CONFIG_ENVIRONMENT =
// PayPalConfiguration.ENVIRONMENT_NO_NETWORK;
private static final String CONFIG_ENVIRONMENT = PayPalConfiguration.ENVIRONMENT_SANDBOX;
// note that these credentials will differ between live & sandbox
// environments.
private static final String CONFIG_CLIENT_ID = "Aeqc2X1rBIEUtDNqsaRNr0h1neFo9QnNmfgmpA3D32uSLaHpGJu9NV1KfMnFmy7O-_hV47I7ST0SXDW2";
private static final int REQUEST_CODE_PAYMENT = 1;
private static final int REQUEST_CODE_FUTURE_PAYMENT = 2;
private static PayPalConfiguration config = new PayPalConfiguration()
.environment(CONFIG_ENVIRONMENT)
.clientId(CONFIG_CLIENT_ID)
// The following are only used in PayPalFuturePaymentActivity.
.merchantName("Hipster Store")
.merchantPrivacyPolicyUri(
Uri.parse("https://www.example.com/privacy"))
.merchantUserAgreementUri(
Uri.parse("https://www.example.com/legal"));
PayPalPayment thingToBuy;
private static Activity activity() {
return com.codename1.impl.android.AndroidNativeUtil.getActivity();
}
public String payPalTest() {
//Activity activity = AndroidNativeUtil.getActivity();
thingToBuy = new PayPalPayment(new BigDecimal("10"), "USD",
"HeadSet", PayPalPayment.PAYMENT_INTENT_SALE);
Intent intent = new Intent(activity(),PaymentActivity.class);
intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);
activity().startActivityForResult(intent, REQUEST_CODE_PAYMENT);
return "test";
}
public boolean isSupported() {
return false;
}
}
I called the method from main class:
MyNative my = (MyNative)NativeLookup.create(MyNative.class);
if(my!= null){
String aa =my.payPalTest();
System.out.println("result::" + aa);
System.out.println("paypalInt" + my.toString());
}
the apk build successfully but getting below error while trigger the code:
android.content.ActivityNotFound
Exception:Unable to find explicit activity class{com.mycompany.myapp/com.paypal.android.sdk.paymentActivity....
It is searching the paypal sdk classes under main project folder structure.Do I need to add the SDK jar under the said structure?
What I need to do to fix the issue.
The code looks fine, I am guessing this is something in the configuration.
Unable to find explicit activity class Payment activity with PayPal SDK in Xamarin on Android
I was trying to make a simple timer in Javafx with a GUI and Timer class. When the start button is pressed, it is supposed to count down from the inputed time and stop when it reaches 0.
I have the remaining time in milliseconds updating in a TextField on the GUI but it only runs for a random number of milliseconds usually between 100-200 and then it freezes up and throws a VERY large number of exceptions.
I tried to pinpoint where the error was coming from, and found there was also a concurrent modification exception as well.
Here is my Timer class:
import java.sql.Time;
/**
* Created by Josh on 19/8/2015.
*/
public class Timer {
private long endTimeMillis;
public Timer(long hours, long minutes, long seconds){
long currentTime = System.currentTimeMillis();
endTimeMillis = ((seconds*1000 + minutes*1000*60 + hours*1000*60*60) + currentTime);
}
public boolean isFinished(){
long currentTime = System.currentTimeMillis();
if(endTimeMillis - currentTime <= 0){
return true;
}else{
return false;
}
}
public long getRemainingTimeMillis(){
long currentTime = System.currentTimeMillis();
return endTimeMillis - currentTime;
}
}
and this is the GUI
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
/**
* Created by Josh on 19/8/2015.
*/
public class GUI extends Application {
private BorderPane root;
Label hoursLabel, minutesLabel, secondsLabel;
TextField hoursTF, minutesTF, secondsTF;
Button startButton;
Label remainingTimeLabel;
TextField remainingTimeTF;
long remainingTime;
#Override
public void start(Stage primaryStage) throws Exception {
root = new BorderPane();
primaryStage.setScene(new Scene(root, 1300, 125));
primaryStage.show();
primaryStage.setResizable(true);
primaryStage.setTitle("Timer");
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
event.consume();
System.exit(0);
}
});
FlowPane center = new FlowPane();
hoursLabel = new Label(" Hours: ");
hoursTF = new TextField();
minutesLabel = new Label(" Minutes: ");
minutesTF = new TextField();
secondsLabel = new Label(" Seconds: ");
secondsTF = new TextField();
center.getChildren().addAll(hoursLabel, hoursTF, minutesLabel, minutesTF, secondsLabel, secondsTF);
root.setCenter(center);
FlowPane bottom = new FlowPane();
bottom.setAlignment(Pos.CENTER);
startButton = new Button("Start");
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
start();
}
});
remainingTimeLabel = new Label(" Time Remaining: ");
remainingTimeTF = new TextField();
bottom.getChildren().addAll(startButton, remainingTimeLabel, remainingTimeTF);
root.setBottom(bottom);
}
public void start(){
Task timer = new Task<Void>() {
#Override
protected Void call() throws Exception {
long hours = 0, minutes = 0, seconds = 0;
try{
if(hoursTF.getText() == null || hoursTF.getText().equals("")){
hours = 0;
}else{
hours = Long.parseLong(hoursTF.getText());
}
if(minutesTF.getText() == null || minutesTF.getText().equals("")){
minutes = 0;
}else{
minutes = Long.parseLong(minutesTF.getText());
}
if(secondsTF.getText() == null || secondsTF.getText().equals("")){
seconds = 0;
}else{
seconds = Long.parseLong(secondsTF.getText());
}
}catch(NumberFormatException e){
System.out.println("Error");
}
Timer timer = new Timer(hours, minutes, seconds);
while(!timer.isFinished()){
remainingTimeTF.setText(Long.toString(timer.getRemainingTimeMillis()));
}
return null;
}
};
new Thread(timer).start();
}
public static void main(String[] args) {
launch(args);
}
}
any help would be appreciated!
New stack trace:
x.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at GUI$3.call(GUI.java:109)
at GUI$3.call(GUI.java:80)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:438)
at javafx.scene.Parent$2.onProposedChange(Parent.java:364)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$$Lambda$102/1442917786.call(Unknown Source)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at GUI$3.call(GUI.java:109)
at GUI$3.call(GUI.java:80)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
You are violating the rule about not accessing the state of a node in a live scene graph on a background thread. Most JavaFX controls will actually check for this and throw an IllegalStateException when you do this: apparently TextInputControl.setText(...) doesn't (presumably for reasons of performance).
The simplest fix is to update the message property of the task:
while(!timer.isFinished()){
updateMessage(Long.toString(timer.getRemainingTimeMillis()));
// remainingTimeTF.setText(Long.toString(timer.getRemainingTimeMillis()));
}
(this causes an update to the message property to occur on the FX Application Thread), and then bind the text field's text property to it:
remainingTimeTF.textProperty().bind(timer.messageProperty());
new Thread(timer).start();
However, there are a lot of things about your code that violate good practice. Fo example, you should really compute the total time outside of the task (i.e. on the FX Application Thread) and store it in a final variable; and the busy while loop is pretty horrible (though updateMessage(...) will fix most of the issues associated with that for you).
I recommend you read up on multithreading in JavaFX. Start with the Task API docs. Maybe this question will help: Using threads to make database requests
First of all, if you really need to update that TextField in the way you are doing it I would recommend adding a Thread.sleep(100); (10 updates per second) in your while, or even Thread.sleep(1000); (1 update per second) since it's really CPU intensive to update that text field on every CPU cycle and usually you don't need to..
Secondly (and probably the reason of your exceptions) the call remainingTimeTF.setText(); MUST happen IN the FX Thread, try this code instead:
Platform.runLater(new Runnable() {
#Override public void run() {
remainingTimeTF.setText(Long.toString(timer.getRemainingTimeMillis()));
}
});
Right now you are setting the text outside the FX Thead which might lead to several exceptions since update requests are happening in a worker thread and the actual UI modifications are happening in the FX thread. You need to make sure that every time you need to modify the UI it happens in the correct thread, in this case the FX Thread with the Platform.runLater() call.
Also since you are already using the Task class why not bind the text property and use the updateMessage() or updateTitle() methods instead?
Take a look at this article, it has good examples for the correct usage of Task and updating the UI from worker threads.
Hope this helps!
I want to create a file input that behaves as follows:
Process the exchange
Attempt to copy the input file to a shared drive
If step (2) fails (e.g. share is down) then move to local file instead
Following the doc the 'moveFailed' parameter allows to "set a different target directory when moving files after processing (configured via move defined above) failed". So this sounds like the moveFailed would cover step (3).
The following test, however fails...what am I doing wrong ? I am using camel 2.10.0.fuse.
package sandbox.camel;
import java.io.File;
import org.apache.camel.Endpoint;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.junit.Test;
public class MoveFailedTest extends org.apache.camel.test.junit4.CamelTestSupport {
private String failedDir = "move-failed";
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("file:tmp/prepare").to("file:tmp/input");
from("file:tmp/input?move=/doesnotexist&moveFailed=" + failedDir).to("file:tmp/output");
}
};
}
#Test
public void test_move() throws Exception {
// arrange
File moveFailedDir = new File("tmp/input/" + failedDir);
moveFailedDir.mkdirs();
File[] failedCount1 = moveFailedDir.listFiles();
failedCount1 = failedCount1 == null ? new File[0] : failedCount1;
String messagePayload = "Hello";
Endpoint input = getMandatoryEndpoint("file:tmp/prepare");
MockEndpoint output = getMockEndpoint("mock:file:tmp/output");
output.setMinimumExpectedMessageCount(1);
output.expectedBodiesReceived(messagePayload);
// act
template.asyncSendBody(input, messagePayload);
Thread.sleep(3000);
// assert: only 1 output
assertMockEndpointsSatisfied();
// assert: renamed failed, hence input file was moved to 'movefailed' directory
File[] failedCount2 = moveFailedDir.listFiles();
assertEquals("No file appeared in 'movefailed' directory", failedCount1.length + 1, failedCount2.length);
}
}
Your test is most likely wrong. The autocreate option is default true, which means directories is created if needed.