Search code examples
javaswingswingworker

Question about threads when running a GUI


Im currently writing a program for Uni that uses RFID trackers to track the movement of RFID tags as they pass through them. This is mimicking the movement of a wallet as it passes through rooms.

I have added a button to my GUI which initializes the trackers and updates my database as the tags pass through them. They stay online for 60 seconds and all work fine. However, once this button is pressed, my GUI freezes until the process has stopped. This prevents a table on my GUI updating.

I realize that i need to use threads, ive found SwingWorker which looks good however after a while of trying to understand it i cant seem to figure it out.

I am wondering if someone with more experience than me could tell me if SwingWorker will work for what i need and give me some advice on how to use it.

Here are some snippets of my code:

Tracking JButton:

JButton trackingButton = new JButton("Start Tracking");
trackingButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        try {
            RFIDHandler.openRFID(); //runs the RFID readers
        } catch (PhidgetException | SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }
});

The start of my openRFID method:

public static void openRFID() throws PhidgetException, SQLException {   

    RFID phid1 = new RFID();
    RFID phid2 = new RFID();
    WalletDAO dao = new WalletDAO();

    // Open and start detecting rfid cards
    phid1.open(5000);  // wait 5 seconds for device to respond
    phid2.open(5000);  // wait 5 seconds for device to respond


    phid1.setAntennaEnabled(true);
    phid2.setAntennaEnabled(true);

    // Make the RFID Phidget able to detect loss or gain of an rfid card
    phid1.addTagListener(new RFIDTagListener() {
        public void onTag(RFIDTagEvent e) {
            try {
                Wallet w = dao.getWallet(e.getTag());                   
                String location = w.getLocation();
                System.out.println(location);

                if(Objects.equals(location, "Room A")) {
                    System.out.println(w.getName() + "'s Wallet read");
                    w.setLocation("Room B");
                    try {
                        dao.updateLocation(w);
                        WalletLocatorInterface.refreshTable(); // refreshes table on GUI
                        System.out.println("Currently in room B");
                    } catch (SQLException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
                // ... else statement + another TagListener 

    System.out.println("Gathering data for 60 seconds\n\n");
    try {
        Thread.sleep(60000);
    } catch (InterruptedException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    phid1.close();
    phid2.close();
    System.out.println("\nClosed RFIDs");
}

Let me know if you need me to clear anything up, thanks.


Solution

  • Your problem is the Thread.sleep. You could accomplish what you are doing here with ScheduledExecutorService. Simply modify your code to this:

    ...
        System.out.println("Gathering data for 60 seconds\n\n");
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    
        Executors.newScheduledThreadPool(1).schedule(() -> {
            phid1.close();
            phid2.close();
            System.out.println("\nClosed RFIDs");
        }, 60, TimeUnit.SECONDS);
    }
    

    (By the way, I used a lambda expression, which can be explained here.)

    Regarding SwingWorker, I don't have much experience. However, with SwingWorker, you can do stuff in the background and not make your GUI stutter when updating. However, if you don't really update the GUI, like @MadProgrammer said, then you wouldn't really benefit from using a SwingWorker.