-1

私は JavaFX 2 を初めて使用し、JavaFX でマルチスレッドを使用する際に問題が発生しています。私が直面している問題は、アプリケーションが単にフリーズし、その理由が見つからないことです。どこかに競合状態があると思いますが、見つけられません。JavaFx のドキュメントにあるように、「Service」を拡張するクラスを作成し、「start()」で実行しています。

public class ProcessadorTarefas extends Service<StatusRetorno>{

    private final ITarefa tarefaPadrao=new TarefaVerificarImpressora();
    private final ITarefa tarefa;
    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    public ProcessadorTarefas(ITarefa tarefa) {
        this.tarefa = tarefa;
    }

    public void processar() {
        if(getState()==State.READY)
            start();
        else
            restart();
    }

    @Override
    protected Task<StatusRetorno> createTask() {
        return new Task<StatusRetorno>() {
            @Override
            protected StatusRetorno call() throws Exception {

                    /*THE CODE FREEZES HERE*/

                StatusRetorno status = tarefaPadrao.processar();
                if (status == StatusRetorno.SUCESSO)
                    status = tarefa.processar();
                return status;
            }
        };
    }
}

「プロセッサ」メソッドを呼び出すクラスは、ProcessadorTarefas クラスの onSuceed、onCancelled、および onFailed をリッスンします。

public abstract class ControladorBase implements IProcessamentoDispatcher, EventHandler<WorkerStateEvent> {

    @Autowired
    protected ControladorDialogoMensagem dialogoMensagem;
    protected ITarefa tarefa;
    protected String mensagem;
    protected Set<IProcessamentoListener> listeners = new ConcurrentSkipListSet<IProcessamentoListener>();

    protected void executarTarefa(ITarefa tarefa) {
        executarTarefa(tarefa, null);
    }

    protected void executarTarefa(ITarefa tarefa, String mensagem) {
        this.tarefa=tarefa;
        this.mensagem=mensagem;
        despacharProcessamento(StatusProcessamento.INICIADO, null);
        final ProcessadorTarefas processador=new ProcessadorTarefas(tarefa);
        processador.setOnSucceeded(this);
        processador.setOnCancelled(this);
        processador.setOnFailed(this);
        processador.processar();
    }

    @Override
    public void handle(WorkerStateEvent evento) {
        StatusRetorno status= (StatusRetorno) evento.getSource().getValue();
        despacharProcessamento(StatusProcessamento.FINALIZADO,status);
        if(status==StatusRetorno.SUCESSO)
            exibirMensagemSucesso();
        else
            exibirMensagemErro(status);
    }

    /*UNIMPORTANT CODE*/

    private void despacharProcessamento(StatusProcessamento statusProcessamento, StatusRetorno statusRetorno) {
        for (IProcessamentoListener listener : listeners)
            listener.processamento(new EventoProcessamento(this, statusProcessamento,statusRetorno));
    }

    /*ADD AND REMOVE LISTENERS CODE*/
}

「call」メソッドでコードがフリーズすると、リスナーが呼び出されず、メイン ダイアログが表示されません。これは、ユーザーがログインした後にこのコードが呼び出されるためです。

追加された情報

このコードは、ログイン ダイアログが閉じられた後、メイン ダイアログが開く前に実行されるため、画面に javafx 要素はありません。

public class App extends Application implements IDadosSubmetidosListener, IProcessamentoListener {

    /*variable declaration ommited*/   

    public static void main(String args[]) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        ApplicationContext contexto = new ClassPathXmlApplicationContext("/spring/appContext.xml");
        App aplicacao = contexto.getBean(App.class);
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
        aplicacao.iniciar();
    }

    private void iniciar() {
        cancelarOperacoesTEF();
        controladorDialogoLogin.adicionarListener(this);

        /*opens login dialog*/

        controladorDialogoLogin.abrir();
    }

    private void verificarDadosEAbrirTelaPrincipal() {

        /*after the user logged in, close login dialog*/

        controladorDialogoLogin.limparListeners();
        controladorDialogoLogin.fechar();
        if (verificadorFuncaoUsuario.usuarioAutorizado()) {
            if (verificadorFuncaoUsuario.usuarioCaixa())
                verificarSeECFValidoECadastrar();
            else
                controladorDialogoPrincipal.abrir();
        } else {
            controladorDialogoMensagem.adicionarListener(this);
            controladorDialogoMensagem.exibirAlerta("Você não tem credenciais que te permitam acessar este sistema!");
        }
    }

    private void verificarSeECFValidoECadastrar() {
        verificadorNumeroSerieECF.adicionarListener(this);

        /*this code call that class shown above*/

        verificadorNumeroSerieECF.verificarNumeroSerieECF();
    }

    private void terminarCadastroECFEAbrirTelaPrincipal() {
        controladorDialogoCadastroECF.limparListeners();
        controladorDialogoCadastroECF.fechar();
        controladorDialogoPrincipal.abrir();
    }
} 

ご覧のとおり、コードはメイン スレッドで呼び出されます。ここでそのコードを呼び出すのが適切ですか、それともダイアログから呼び出す必要がありますか?

4

1 に答える 1

0

Service クラスが JavaFX コンポーネントから呼び出された場合にのみ機能することを知りませんでした。そこで、この問題を解決するために、コードのこの部分をシングル スレッドで実行するようにしました。プログラムの他の部分では、サービスは JavaFX のコンポーネント (ボタンなど) から開始され、うまく機能します。

于 2013-04-10T12:22:44.870 に答える