NullPointerException in JavaFX initialize method


Question

I have controller and there I trying get INBOX folder from e-mail server. With downloading everything is ok. I can put this data(email subject,from,date) into TableView but... only when I am waiting for thread responsible for set this data in TableView. Code:

// The table and columns
@FXML
TableView<MainModel.Item> itemTbl;
@FXML
TableColumn itemNameCol;
@FXML
TableColumn itemQtyCol;
@FXML
TableColumn itemTitleCol;
// The table's data
static ObservableList<MainModel.Item> data;

public void dataSet(){
    // Set up the table data
    itemNameCol.setCellValueFactory(
        new PropertyValueFactory<MainModel.Item,String>("name")
    );
    itemQtyCol.setCellValueFactory(
        new PropertyValueFactory<MainModel.Item,String>("qty")
    );
    itemTitleCol.setCellValueFactory(
        new PropertyValueFactory<MainModel.Item,String>("title")
    );

    data = FXCollections.observableArrayList();
    itemTbl.setItems(data);
}

public void setEnemyEvent() {
    itemTbl.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            if (event.getClickCount() == 2) {
                if(itemTbl.getSelectionModel().getSelectedItem()!=null){
                    System.out.println(itemTbl.getSelectionModel().getSelectedItem().name);
                }
            }
        }
    });
}

@Override
public void initialize(URL url, ResourceBundle rb) { 
    setEnemyEvent();
    dataSet();
    Thread t = new Thread(new MessageLoop());
    //HERE:
    t.start();
    //of course normally here is try and catch
    t.join();
}

//staric nested class "for loop"
private static class MessageLoop implements Runnable {
    public void run() {
        try {
            EmailConnetion con = new EmailConnetion();
            MainModel MainModel = new MainModel();
            for(int i=0;i<con.message.length;i++){
                try{
                    MainModel.Item item = MainModel.new Item();
                    item.name.setValue(i+""+con.message[i].getFrom()[0].toString());
                    item.qty.setValue(con.message[i].getSentDate().toString());
                    item.title.setValue(con.message[i].getSubject().toString());
                    //Here is a problem.
                    data.add(item);//This indicate my IDE  
                    //*****************
                } catch(AddressException e) {
                    System.out.println("Error : " + "AddressException:"+i);
                }
            }
        } catch (NoSuchProviderException ex) {
            Logger.getLogger(SimpleController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MessagingException ex) {
            Logger.getLogger(SimpleController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

When i remove t.join() it will throw this NullPointerException.

Exception in thread "Thread-3" java.lang.NullPointerException
    at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:291)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:48)
    at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(ReadOnlyUnbackedObservableList.java:74)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel$3.onChanged(TableView.java:1725)
    at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:134)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:48)
    at com.sun.javafx.collections.ObservableListWrapper.callObservers(ObservableListWrapper.java:97)
    at com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:184)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel.quietClearSelection(TableView.java:2154)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel.updateSelection(TableView.java:1902)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel.access$2600(TableView.java:1681)
    at javafx.scene.control.TableView$TableViewArrayListSelectionModel$8.onChanged(TableView.java:1802)
    at com.sun.javafx.scene.control.WeakListChangeListener.onChanged(WeakListChangeListener.java:71)
    at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:291)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:48)
    at com.sun.javafx.collections.ObservableListWrapper.callObservers(ObservableListWrapper.java:97)
    at com.sun.javafx.collections.ObservableListWrapper.add(ObservableListWrapper.java:154)
    at com.sun.javafx.collections.ObservableListWrapper.add(ObservableListWrapper.java:144)
    at javasplitpane.SimpleController$MessageLoop.run(SimpleController.java:95)
    at java.lang.Thread.run(Thread.java:722)

This appear in different position, in fourteen email, thirty email. You have some ideas ?

p.s I can't wait for this downloading because it takes 20 sec. with 50 emails - I have to do it during initialize.

1
5
3/8/2013 10:36:48 PM

Accepted Answer

Your Error

Don't modify anything which is connected to the active scene graph from any other thread than the JavaFX Application Thread.

Background Information

See the JavaFX Concurrency Tutorial and also Usage of JavaFX Platform.runLater and access to UI from a different thread for an explanation of this rule.

As your data list is an ObservableList backing a TableView displayed in the active scene graph, as you modify the ObservableList, it fires change events to the TableView modifying it from your user thread rather than the JavaFX Application Thread - this causes race conditions and inconsistent program failures.

How to Fix it

To fix your issue, wrap the call to update the data item inside Platform.runLater:

Platform.runLater(new Runnable() {
  @Override public void run() {
    data.add(item);
  }
});

The contents of the run method submitted to Platform.runLater are executed on the JavaFX Application Thread.

10
5/23/2017 12:02:11 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon