2016-12-04 14 views
0

私はJavaFXを習得しており、タスクの実行に支障をきたしています。 NetBeansデバッガで作業の進捗状況を追跡した結果、ConfigModelSansUpdateTaskがはっきりと実行されることがわかりました。JavaFX ExecutorServiceがタスクの結果を失う

アプリケーションがconfigModelWorkerSansUpdates.setOnSucceededになると、(configModelに格納されている)何とかこの結果はNullPointerExceptionを投げ、nullなります。

NullPointerExceptionの投稿を読んでいると、なぜ私の仕事の結果が否定されているのかが賢明ではありません。

NetBeans

:タスクは結果を返すために約あるときの

スナップショット:私はそれを使用するために来るとき、私ははっきりと、その後はゼロになるという結果を得て、これを行い明白なものはありませんそして、私は結果を使用するようになったとき:

Null result

ヘルプを!

SWMUApp.java

/* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package swmuapp; 

import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 
import javafx.stage.Stage; 
import jaxb.TaskModel; 

/** 
* 
* @author Shaun Connelly-Flynn 
*/ 

public class SWMUApp extends Application { 

public SWMUApp() { 
} 

@Override 
public void start(Stage stage) throws Exception { 
    FXMLLoader centralSeceneLoader = new FXMLLoader(getClass().getResource("forms/CentralScene.fxml")); 
    Parent centralRoot = (Parent) centralSeceneLoader.load(); 

    Scene scene = new Scene(centralRoot); 

    stage.setScene(scene); 
    stage.show(); 
} 

/** 
* @param args the command line arguments 
*/ 
public static void main(String[] args) { 
    launch(args); 
} 

}

CentralSceneController.java

package swmuapp.controllers; 

import java.net.URL; 
import java.util.ResourceBundle; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.Future; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javafx.concurrent.WorkerStateEvent; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.control.Tab; 
import jaxb.TaskModel; 
import swmuapp.SWMUApp; 
import swmuapp.init.ConfigModelWorkerSansUpdates; 
import swmuapp.init.LocationModelWorker; 
import swmuapp.models.ConfigModel; 
import swmuapp.models.LocationModel; 

/** 
* FXML Controller class 
* 
* @author Shaun Connelly-Flynn 
*/ 

public class CentralSceneController implements Initializable { 

    @FXML 
    private Tab sessionTab; 
    @FXML 
    private Tab tractionTab; 
    @FXML 
    private Tab locationTab; 
    @FXML 
    private Tab swmuTab; 
    @FXML 
    private Tab exportTab; 

    private final TaskModel taskModel; 

    // Models 
    private ConfigModel configModel; 
    private LocationModel locationModel; 

    // Child Controllers 
    @FXML 
    private ImportPaneController importPaneController; 

    @FXML 
    private SWMUPaneController swmuPaneController; 

    @FXML 
    private SessionPaneController sessionPaneController; 

    public CentralSceneController() { 
     this.taskModel = new TaskModel(); 
    } 

    /** 
    * Initialises the controller class. 
    * 
    * @param url 
    * @param rb 
    */ 
    @Override 
    public void initialize(URL url, ResourceBundle rb) { 
     // Give a reference of this controller to the child controllers 
     importPaneController.setParentController(this); 

     // Now subimt the configModel task 
     ConfigModelWorkerSansUpdates configModelWorkerSansUpdates = new ConfigModelWorkerSansUpdates(taskModel); 

     configModelWorkerSansUpdates.setOnSucceeded((WorkerStateEvent event) -> { 
      System.out.println(event.getEventType().toString()); 

      // Get the location model 
      Future<LocationModel> locationFuture = taskModel.submitTask(new LocationModelWorker(configModel, taskModel)); 

      try { 
       locationModel = locationFuture.get(); 
      } catch (InterruptedException | ExecutionException ex) { 
       Logger.getLogger(SWMUApp.class.getName()).log(Level.SEVERE, null, ex); 
      } 

      // Notify the controllers that we're ready 
      sessionPaneController.setConfigModel(configModel); 
      sessionPaneController.setLocationModel(locationModel); 
     }); 

     configModelWorkerSansUpdates.setOnFailed(p -> System.out.println(p.toString())); 
     configModelWorkerSansUpdates.setOnCancelled(p -> System.out.println(p.toString())); 

     // Fetch the config model 
     Future<ConfigModel> configFuture = taskModel.submitTask(configModelWorkerSansUpdates); 

     try { 
      configModel = configFuture.get(); 
     } catch (InterruptedException | ExecutionException ex) { 
      Logger.getLogger(SWMUApp.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 

TaskModel.java

/* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package jaxb; 

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.Callable; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import javafx.concurrent.Task; 

/** 
* 
* @author Shaun Connelly-Flynn 
*/ 
public class TaskModel { 
    private final ExecutorService service; 

    public TaskModel() { 
     this.service = Executors.newCachedThreadPool(); 
    } 

    public Future submitTask(Callable task) { 
     return service.submit(task); 
    } 

    public Future submitTask(Task task) { 
     return service.submit(task); 
    } 

    public List<Future> submitTasks(List<Callable> tasks) { 
     List<Future> futureList = new ArrayList<>(); 

     for(Callable task : tasks) { 
      futureList.add(submitTask(task)); 
     } 

     return futureList; 
    } 
} 

ConfigModelWorkerSansUpdates.java

/* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package swmuapp.init; 

import java.util.concurrent.ExecutionException; 
import java.util.concurrent.Future; 
import javafx.concurrent.Task; 
import jaxb.Binder; 
import jaxb.TaskModel; 
import jaxb.bundles.QueryBundle; 
import jaxb.bundles.ResultsBundle; 
import jaxb.query.XQuery; 
import swmuapp.config.jaxb.JaxbConfig; 
import swmuapp.config.jaxb.JaxbDatabases; 
import swmuapp.models.ConfigModel; 

/** 
* 
* @author Shaun Connelly-Flynn 
*/ 
public class ConfigModelWorkerSansUpdates extends Task<ConfigModel> { 

    private final TaskModel taskModel; 

    public ConfigModelWorkerSansUpdates(TaskModel taskModel) { 
     this.taskModel = taskModel; 
    } 

    @Override 
    protected ConfigModel call() throws Exception {   
     // Get the list of active databases 
     QueryBundle databaseBundle = new QueryBundle(
       new XQuery("SWMUDB", "<databases>{databases/database}</databases>"), 
       JaxbDatabases.class, 
       "src/swmuapp/schema/DatabaseSchema.xsd"); 

     // Now read the configuration 
     QueryBundle configBundle = new QueryBundle(
       new XQuery("SWMUDB", "configs/config"), 
       JaxbConfig.class, 
       "src/swmuapp/schema/ConfigSchema.xsd"); 

     // Submit the tasks 
     Future<ResultsBundle> dbTask = taskModel.submitTask(new Binder(databaseBundle, taskModel)); 
     Future<ResultsBundle> configTask = taskModel.submitTask(new Binder(configBundle, taskModel)); 

     // Create empty objects in case of failure! 
     JaxbDatabases dbResult = new JaxbDatabases(); 
     JaxbConfig configResult = new JaxbConfig(); 

     try { 
      // Now fetch the list of databases 
      dbResult = (JaxbDatabases) dbTask.get().getResult(); 

      // Fetch the configuration 
      configResult = (JaxbConfig) configTask.get().getResult(); 
     } catch (ExecutionException ex) { 
      setException(ex); 
      throw ex; 
     } 

     // Now put it all together 
     ConfigModel configModel = new ConfigModel(dbResult); 

     // And give it back! 
     return configModel; 
    } 
} 

SessionPaneController.java

package swmuapp.controllers; 

import java.net.URL; 
import java.util.ResourceBundle; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.control.ListView; 
import javafx.scene.control.TableView; 
import swmuapp.models.ConfigModel; 
import swmuapp.models.LocationModel; 

/** 
* FXML Controller class 
* 
* @author Shaun Connelly-Flynn 
*/ 
public class SessionPaneController implements Initializable { 

    @FXML 
    private ListView<String> dbListView; 
    @FXML 
    private TableView<?> detailedTableView; 

    private CentralSceneController controller; 

    private ConfigModel configModel; 
    private LocationModel locationModel; 

    /** 
    * Initializes the controller class. 
    */ 
    @Override 
    public void initialize(URL url, ResourceBundle rb) { 

    } 

    public void setConfigModel(ConfigModel configModel) { 
     if (this.configModel == null) { 
      this.configModel = configModel; 
     } else { 
      throw new IllegalArgumentException("SessionPaneController::setConfigModel -- config model already set!"); 
     } 

     dbListView.setItems(configModel.getDatabases()); 
    } 

    public void setLocationModel(LocationModel locationModel) { 
     this.locationModel = locationModel; 
    } 

    protected void setParentController(CentralSceneController controller) { 
     this.controller = controller; 
    } 
} 

スタック:

java.util.concurrent.ExecutionException: java.lang.NullPointerException 
    at java.util.concurrent.FutureTask.report(FutureTask.java:122) 
    at java.util.concurrent.FutureTask.get(FutureTask.java:192) 
    at swmuapp.controllers.CentralSceneController.lambda$initialize$0(CentralSceneController.java:84) 
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) 
    at javafx.event.Event.fireEvent(Event.java:198) 
    at javafx.concurrent.EventHelper.fireEvent(EventHelper.java:219) 
    at javafx.concurrent.Task.fireEvent(Task.java:1356) 
    at javafx.concurrent.Task.setState(Task.java:723) 
    at javafx.concurrent.Task$TaskCallable.lambda$call$500(Task.java:1434) 
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294) 
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) 
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: java.lang.NullPointerException 
    at swmuapp.init.LocationModelWorker.call(LocationModelWorker.java:35) 
    at swmuapp.init.LocationModelWorker.call(LocationModelWorker.java:22) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    ... 1 more 

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException 
    at swmuapp.controllers.SessionPaneController.setConfigModel(SessionPaneController.java:49) 
    at swmuapp.controllers.CentralSceneController.lambda$initialize$0(CentralSceneController.java:90) 
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) 
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) 
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) 
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) 
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) 
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) 
    at javafx.event.Event.fireEvent(Event.java:198) 
    at javafx.concurrent.EventHelper.fireEvent(EventHelper.java:219) 
    at javafx.concurrent.Task.fireEvent(Task.java:1356) 
    at javafx.concurrent.Task.setState(Task.java:723) 
    at javafx.concurrent.Task$TaskCallable.lambda$call$500(Task.java:1434) 
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294) 
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) 
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) 
    at java.lang.Thread.run(Thread.java:745) 
+2

[NullPointerExceptionとは何ですか?それを修正するにはどうすればいいですか?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix -it) –

+0

デバッガでコードを実行した後、私は賢明ではありません。 – swshaun

答えて

0

他の投稿からさらに詳しい情報が見つかりました!この記事で述べたようにTaskRunnableのサブクラスではないCallable

です:未来のgetメソッドが正常に完了した場合はnullを返します

FX Task, returning a value always returns null

Javadocがあることを示しています。

上記のJavadocについては、hereを参照してください。

Taskは実際にはそうでない場合、Callableの実装であるという誤った仮定をしました。

したがって、Runnableは返品の結果がないため、Future.get()は正常終了時にnullを返します。

1

私はFuture.get戻る前に実行されるonSucceededハンドラにつながるスケジューリングの決定のいくつかの組み合わせを疑うので、CentralSceneController.configModelまだしていません割り当てられました。

Future.get()同じスレッドからタスクを送信した直後は、現在のスレッドが強制的にタスクの完了を待つため、この時間を使用して直接質問を実行する可能性があるため、何もしません。 javafxアプリケーションスレッドのように、ブロックすべきではない現在のスレッドであればさらに悪いことです。これを修正

は簡単なはず:

ただ、このハンドラがとにかくアプリケーションスレッドのタスクの完了後にトリガされているので、onSucceededハンドラから値を取得し、値を取得するには、このメソッドを使用すると、アプリケーションをブロックしません糸。

次のコードはLocationModelWorkerがconstuctorパラメータの代わりConfigModelパラメータとしてFuture<ConfigModel>を取るTask<LocationModel>

リライトLocationModelWorkerを拡張前提。 メソッドが開始されるまで(例えば、コンストラクタから呼び出さないでください)、がFutureに呼び出されていないことを確認してください。

configModelWorkerSansUpdates.setOnSucceeded((WorkerStateEvent event) -> { 
    sessionPaneController.setConfigModel(configModelWorkerSansUpdates.getValue()); 
}); 

... 

Future<ConfigModel> configFuture = taskModel.submitTask(configModelWorkerSansUpdates); 

LocationModelWorker locationModelWorker = new LocationModelWorker(configFuture, taskModel); 
locationModelWorker.setOnSucceeded(evt -> { 
    sessionPaneController.setLocationModel(locationModelWorker.getValue()); 
}); 

... 

taskModel.submitTask(locationModelWorker); 

あなたは、あなただけ正常に完了し、両方のタスク場合setLocationModelsetConfigModelを呼び出したい場合は、このビットを調整する必要があります。

+0

ありがとうございます。私は 'onSucceeded'ハンドラから結果を取得しようとしましたが、ハンドラ内で' configModel = configFuture.get(); 'を使って同じ問題が発生しています。私は間違った場所で自分のモデルを初期化するなど、重大な間違いをしていますか? – swshaun

+0

また、 'configFuture.outcome'の内容もnullであることに注意してください。 – swshaun

+0

そのことありがとうございます。私はあなたの答えを受け入れました – swshaun

関連する問題