Call function every x time without blocking the GUI Java

后端 未结 3 1844
余生分开走
余生分开走 2021-01-23 02:31

I have a class caled ItemGUI which is handling everything related with the user interface. The user, is able to add some links, which are the items, so when he inserts a link an

3条回答
  •  萌比男神i
    2021-01-23 02:59

    Update

    The clearest solution by MadProgrammer's suggestion is to use swing Timers, like this:

    protected javax.swing.Timer refresherTimer = null;
    protected void stopRefreshing() {
        if (refresherTimer != null) {
            refresherTimer.stop();
            refresherTimer = null;
        }
    }
    protected void startRefreshing() {
        stopRefreshing();
        refresherTimer = new Timer(500, e -> {
            newItem.getPrice()
        });
        refresherTimer.start();
    }
    public void onStartButtonClicked() {
        Item newItem = new Item(newItemField.getText());
        // here newItem should be added to a list of items which should be in the ItemGUI class
        startRefreshing();
    }
    public void onStopButtonClicked() {
        stopRefreshing();
    }
    

    Original answer

    It would be nice to have some utility named e.g. GuiTimer which would make your task as easy as:

    protected GuiThread.Task refresherTask = null;
    protected void cancelRefreshing() {
        if (refresherTask != null) {
            refresherTask.cancel();
            refresherTask = null;
        }
    }
    public void onStartButtonClicked() {
        Item newItem = new Item(newItemField.getText());
        // should also be added to a list of items which should be in the ItemGUI class
        cancelRefreshing();
        refresherTask = GuiThread.scheduleAtFixedRate(() -> {
            newItem.getPrice()
        }, 0, 5, TimeUnit.SECONDS);
    }
    public void onStopButtonClicked() {
        cancelRefreshing();
    }
    

    The problem with regular timers is that they invoke the callback function on their own thread, not on the gui thread, so it requires the developer to ensure proper threading. Unfortunately the builtin java EventQueue does not support dispatching delayed tasks.

    For this reason I like to have the following utility called GuiTimer, which will act as a pure gui-threaded timer:

    public class GuiTimer {
        public static final ScheduledThreadPoolExecutor executor = 
                new ScheduledThreadPoolExecutor(1);
    
        public static interface Task {
            public void cancel();
        }
    
        private static class CancelStateTask implements Task {
            public volatile boolean canceled = false;
    
            @Override
            public void cancel() {
                this.canceled = true;
            }
        }
    
        public static Task schedule(final Runnable action) {
            CancelStateTask task = new CancelStateTask();
            EventQueue.invokeLater(() -> {
                if (!task.canceled)
                    action.run();
            });
            return task;
        }
    
        public static Task schedule(final Runnable command, long delay,
                TimeUnit unit) {
            ScheduledFuture future = executor.schedule(
                    () -> EventQueue.invokeLater(command), delay, unit);
            return () -> future.cancel(false);
        }
    
        public static Task scheduleAtFixedRate(Runnable command,
                long initialDelay, long period, TimeUnit unit) {
            ScheduledFuture future = executor.scheduleAtFixedRate(
                    () -> EventQueue.invokeLater(command), initialDelay,
                    period, unit);
            return () -> future.cancel(false);
        }
    
        public static Task scheduleWithFixedDelay(Runnable command,
                long initialDelay, long delay, TimeUnit unit) {
            ScheduledFuture future = executor.scheduleAtFixedRate(
                    () -> EventQueue.invokeLater(command), initialDelay, delay,
                    unit);
            return () -> future.cancel(false);
        }
    
        public static void shutdown() {
            executor.shutdown();
        }
    }
    

提交回复
热议问题