JavaFX应用程序在加载许多图像时冻结几秒钟,尽管它们在后台线程中加载它们

时间:2013-12-26 21:46:02

标签: java multithreading javafx javafx-2 javafx-8

我创建了一个类作为加载器,用于在后台线程中加载图像,将它们添加到JavaFX应用程序中,

我的问题是,虽然这个类可以作为一个任务,但它会导致JavaFX Apllication在图像加载过程中冻结,并在完成后再正常工作,

Loader类代码:

import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

public class Loader{
    private String type     = "";
    private String url      = "";
    private ImageView image = new ImageView();

    private class LoaderService extends Service{
        @Override
        protected Task createTask() {
            return new LoaderTask();
        }
    }

    private class LoaderTask extends Task{
        @Override
        protected Object call() throws Exception {
            new LoaderClass();

            return null;
        }
    }

    private String getType(){
        return this.type;
    }

    private String getUrl(){
        return this.url;
    }

    public Loader type(String type){
        this.type = type;
        return this;
    }

    public Loader url(String url){
        this.url = url;
        return this;
    }

    public ImageView getImage(){
        return this.image;
    }

    public Loader build(){
        new LoaderTask().run();
        return this;
    }

    private class LoaderClass{
        public LoaderClass(){
            switch(getType()){
                case "image":
                    this.loadImage(getUrl());
                break;
            }
        }

        private void loadImage(String url){
            try{
                getImage().setImage(new Image(url));
            }catch(Exception ex){
                System.out.println("Ex"+ex.getMessage());
            }
        }
    }
}

从外部类调用加载器以将其添加到主JavaFX窗口中的示例:

StackPane Pane = new StackPane();

ImageView Icon1 = new NinjaLoader()
                                    .type("image")
                                    .url("http://localhost/images/1.png")
                                    .build()
                                    .getImage();

ImageView Icon2 = new NinjaLoader()
                                    .type("image")
                                    .url("http://localhost/images/2.png")
                                    .build()
                                    .getImage();

ImageView Icon3 = new NinjaLoader()
                                    .type("image")
                                    .url("http://localhost/images/3.png")
                                    .build()
                                    .getImage();

ImageView Icon4 = new NinjaLoader()
                                    .type("image")
                                    .url("http://localhost/images/4.png")
                                    .build()
                                    .getImage();
Pane.getChildren().addAll(Icon1,Icon2,Icon3,Icon4);

那么我的代码中导致这些冻结的错误是什么?

谢谢,

2 个答案:

答案 0 :(得分:20)

您根本不需要管理线程来在后台线程中加载图像:Image构造函数有一个标志来执行此操作。只是做

ImageView icon1 = new ImageView(new Image("http://localhost/images/1.png", true));

答案 1 :(得分:4)

问题是您通过调用run的{​​{1}}方法在同一个线程中运行您的任务:

Runnable

通常的做法是在线程(简单)中运行它:

new LoaderTask().run();

或将其发送到线程池(更多工作)。 More on this in the related Oracle docs...

<强>更新

如果它仍然冻结:

  • 确保您不执行任何I / O,即读取FX线程中的文件或资源,因为这会阻止UI更新导致冻结。 FX线程是您可以从中更新UI属性的线程。
  • 尝试在单独的线程中加载资源,并在运行Thread th = new Thread(new LoaderTask()); th.setDaemon(true); th.start(); 时将部分/全部内容加载到内存中后立即更新。