JavaFX UI在Web服务调用上冻结

时间:2015-04-20 13:11:47

标签: javafx jersey fxml

我有一个JavaFX应用程序,它通过Jersey客户端API消耗Web服务,每隔一段时间应用程序(屏幕)的一部分就会冻结,同时执行对Web服务的调用。

我没有用于进行Web服务调用的线程。

以下是泽西岛客户代码:

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;
    public class WSClient{
        WebResource webResource;
        ClientResponse response;

        protected Client getWSClient() {

            ClientConfig clientConfig = new DefaultClientConfig();

            clientConfig.getFeatures().put(
                    JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);

            Client wsClient = Client.create(clientConfig);
            return wsClient;
        }

        public ArrayList<String> getNames(){
            ArrayList<String> names= new ArrayList<>();

            try{
                webResource = getWSClient().resource("http://localhost:8080/names");
                response = webResource.type("application/json").accept("application/json").get(ClientResponse.class);

            }catch(Exception ex){
                log.error("Failed : " + ex.getMessage());
                return null;
            }
            if(response.getStatus() != 200){
                return null;
            }
            String output = response.getEntity(String.class);
            names= getGson().fromJson(output,
                    new TypeToken<ArrayList<String>>() {
                    }.getType());



            return names;
        }
    }

以下是JavaFX控制器类:

private ComboBox<String> cmbNames = new ComboBox<>();

cmbNames.setItems(FXCollections.observableList(new WSClient().getNames()));

非常感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

从服务器检索数据是或者至少有可能是长期运行的操作。您不应该在FX应用程序线程上执行此类操作,因为UI在操作期间将无响应。

创建Task以执行操作,并在后台线程中执行:

Task<List<String>> getNamesTask = new Task<List<String>>() {
    @Override
    public List<String> call() {
        return new WSClient().getNames();
    }
};

getNamesTask.setOnSucceeded(e -> 
    cmbNames.getItems().setAll(getNamesTask.getValue()));

要在后台线程中执行任务,您可以“手动”执行此操作:

Thread thread = new Thread(getNamesTask);
thread.setDaemon(true);
thread.start();

或者(更好),使用Executor来管理线程池:

// declared at class level:
private final Executor exec = Executors.newCachedThreadPool(runnable -> {
    Thread t = new Thread(runnable);
    t.setDaemon(true);
    return t ; 
});

// ...

exec.execute(getNamesTask);

有关将客户端 - 服务器通信与JavaFX集成的更多策略,请查看Adam Bien's excellent article