JavaFX UI 在 Web 服务调用时冻结



我有一个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()));

非常感谢您的帮助!

从服务器检索数据是,或者至少有可能是一个长时间运行的操作。不应在 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的优秀文章。

最新更新