WatchService and SwingWorker: how to do it correctly?

前端 未结 3 1496

WatchService sounded like an exciting idea ... unfortunately it seems to be as low-level as warned in the tutorial/api plus doesn\'t really fit into the Swing event model (o

3条回答
  •  甜味超标
    2020-11-30 09:56

    Actually, @Eels's comment didn't stop knocking in the back of my head - and finally registered: it's the way to go, but there is no need for any "artificial" struct, because we already have the perfect candidate - it's the PropertyChangeEvent itself :-)

    Taking the overall process description from my question, the first three bullets remain the same

    • same: extend SwingWorker
    • same: do the registration stuff in the constructor
    • same: put the endless loop waiting for a key in doInBackground
    • changed: create the appropriate PropertyChangeEvent from each WatchEvent when retrieved via key.pollEvents and publish the PropertyChangeEvent
    • changed: fire the previously created event in process(chunks)

    Revised FileWorker:

    @SuppressWarnings("unchecked")
    public class FileWorker extends SwingWorker {
    
        public static final String FILE_DELETED = StandardWatchEventKinds.ENTRY_DELETE.name();
        public static final String FILE_CREATED = StandardWatchEventKinds.ENTRY_CREATE.name();
        public static final String FILE_MODIFIED = StandardWatchEventKinds.ENTRY_MODIFY.name();
    
        // final version will keep a map of keys/directories (just as in the tutorial example) 
        private Path directory;
        private WatchService watcher;
    
        public FileWorker(File file) throws IOException {
            directory = file.toPath();
            watcher = FileSystems.getDefault().newWatchService();
            directory.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
        }
    
        @Override
        protected Void doInBackground() throws Exception {
            for (;;) {
                // wait for key to be signalled
                WatchKey key;
                try {
                    key = watcher.take();
                } catch (InterruptedException x) {
                    return null;
                }
    
                for (WatchEvent event : key.pollEvents()) {
                    WatchEvent.Kind kind = event.kind();
                    // TBD - provide example of how OVERFLOW event is handled
                    if (kind == OVERFLOW) {
                        continue;
                    }
                    publish(createChangeEvent((WatchEvent) event, key));
                }
    
                // reset key return if directory no longer accessible
                boolean valid = key.reset();
                if (!valid) {
                    break;
                }
            }
            return null;
        }
    
        /**
         * Creates and returns the change notification. This method is called from the 
         * worker thread while looping through the events as received from the Watchkey.
         * 
         * @param event
         * @param key
         */
        protected PropertyChangeEvent createChangeEvent(WatchEvent event, WatchKey key) {
            Path name = event.context();
            // real world will lookup the directory from the key/directory map
            Path child = directory.resolve(name);
            PropertyChangeEvent e = new PropertyChangeEvent(this, event.kind().name(), null, child.toFile());
            return e;
        }
    
        @Override
        protected void process(List chunks) {
            super.process(chunks);
            for (PropertyChangeEvent event : chunks) {
                getPropertyChangeSupport().firePropertyChange(event);
            }
        }
    }
    

提交回复
热议问题