Java Swing Worker for Progress Bar - UI remains unresponsive for a long time -


i developed application on windows using java, swing (window builder).
on button click, application go class (filemanager.java file) count total number of files in input folder (meanwhile progressbar in indeterminate mode). once number of files known, progressbar maximum value set.

then call converttoxls(filemgr) read through content of each file (1 kb) , update progressbar each file read.

here code it:

public class xmltoxl {             public static void main(string[] args) {         javax.swing.swingutilities.invokelater(new runnable() {             public void run() {                 xmltoxl window = new xmltoxl();                 window.frame.setvisible(true);             }         });         private void initialize() {             ...... ui code ........         btnconvertxmlto.addactionlistener(new actionlistener() {             public void actionperformed(actionevent e) {                     try {                     preconverttoxls();                     task task = new task(folderpath.gettext());                     task.execute();                 } catch (exception e1) {                     e1.printstacktrace();                 }             }// end of actionperformed method         }); // end of action listened  }//end of initialize      public void preconverttoxls() {    //method set few ui properties         btnconvertxmlto.setenabled(false);         progressbar.setvisible(true);         progressbar.setstringpainted(true);         progressbar.setindeterminate(true);         progressbar.setstring("calculating total number of files...");         progressbar.setforeground(new color(0, 102, 0));     }      parserutils parutils = new parserutils(); //class parse xml files (in .java file)      private void converttoxls(filemanager filemgr) {         try {             int i=1;             parutils.reset();             progressbar.setvalue(0);             list<file> files = filemgr.getfiles();             for(file file : files) {                 progressbar.setstring("reading " + i+ " of " + filemgr.getsize()+ " files");                 parutils.parsefileusingdom(file); // read content of input file                  progressbar.setvalue(i++);             }             btnconvertxmlto.setenabled(true);           } catch (exception e) {          }      }      class task extends swingworker<void, void> {         private filemanager filemgr;          public task(string srcpath) {             this.filemgr = new filemanager(new file(srcpath));          }          /*          * main task. executed in background thread.          */         @override         public void doinbackground() {             try {                 progressbar.setindeterminate(true);                 filemgr.readfiles();                 progressbar.setindeterminate(false);                 progressbar.setmaximum(filemgr.getsize());                 converttoxls(filemgr);             } catch (exception e) {                 e.printstacktrace();             }             return null;         }          /*          * executed in event dispatching thread          */         @override         public void done() {             toolkit.getdefaulttoolkit().beep();             try {             progressbar.setstring("fileread successful");             } catch (exception e) {                 // todo auto-generated catch block                 e.printstacktrace();             }         }     }//end of task class }//end of class 

my ui becomes unresponsive after filemgr.readfiles();. takes minute or two, 3 , executes converttoxls(filemgr).

filemanager.java

import xmlparsing.determineencoding;  public class filemanager {      public hashmap<string, arraylist<string>> dirfiles = null;     public arraylist<string> dirnames = null;     public int numberoffiles;     private file src;     private list<file> files;      public filemanager(file src) {         this.src = src;         dirnames = new arraylist<string>();         dirfiles = new hashmap<string, arraylist<string>>();         numberoffiles = 0;         files = new arraylist<file>();     }        public int getsize() {         return numberoffiles;     }      public arraylist<string> getdirectories(){         return dirnames;     }      public list<file> getfiles() {         iterator = dirfiles.entryset().iterator();         while (it.hasnext()) {             map.entry pair = (map.entry) it.next();             string foldername = (pair.getkey()).tostring();             arraylist<string> filenames = (arraylist<string>) pair.getvalue();             if (filenames != null) {                 (string filename : filenames) {                     if(replaceselected(filename)) {                         file fxmlfile = new file(filename);                         files.add(fxmlfile);                     }                     else {                     }                 }             }         }         return files;     }      public void readfiles() throws ioexception {         readfiles(src);     }      private void readfiles(file folder) throws ioexception {         if (folder.isdirectory()) {             arraylist<string> filenames = new arraylist<string>();             (final file file : folder.listfiles()) {                 if (file.isdirectory()) {                     readfiles(file);                 } else {                     string filename = (file.getpath()).tostring();                     if(filename.tolowercase().endswith(".xml")) {                         filenames.add(file.getpath());                         numberoffiles = numberoffiles + 1;                         system.out.println(".");                         if(!dirnames.contains(file.getparentfile().getname()))                                 dirnames.add(file.getparentfile().getname());                     }                 }             }             dirfiles.put(folder.getname(), filenames);         }     }      private boolean replaceselected(string filepath) {         string line;         string input = "";         try {             determineencoding de = new determineencoding();             string encoding = de.getfileencoding(filepath);             inputstreamreader file = new inputstreamreader(new fileinputstream(                     filepath), encoding);             bufferedreader br = new bufferedreader(file);             while ((line = br.readline()) != null) {                 input += line.tostring() + " ";             }             file.close();             writer out = new bufferedwriter(new outputstreamwriter(                     new fileoutputstream(filepath), "utf-8"));             out.append(input.trim());             out.flush();             out.close();         } catch (exception e) {             return false;         }         return true;     }  } 

determineencoding.java

import java.io.fileinputstream; import java.io.filenotfoundexception; import java.io.ioexception;  import org.mozilla.universalchardet.universaldetector;  public class determineencoding {      public determineencoding() {         // todo auto-generated constructor stub     }      public string getfileencoding(string filename) throws ioexception {         byte[] buf = new byte[4096];         java.io.fileinputstream fis = new fileinputstream(filename);         universaldetector detector = new universaldetector(null);         int nread;         while ((nread = fis.read(buf)) > 0 && !detector.isdone()) {           detector.handledata(buf, 0, nread);         }         detector.dataend();         string encoding = detector.getdetectedcharset();         if (encoding != null) {           return encoding;         } else {           return "";         }       }  } 

please me identify issue.

the basic problem 1 of perception. "think" ui isn't responding, when in fact, it's waiting.

when call readfiles, goes through files have scanned for, reads them , writes them out again, while progress bar in "determinate" mode, doesn't display anything.

what need way filemanager provide updates it's progress worker, worker goes through number of other methods, have provide progress notifications.

this seem hint @ need kind of observer pattern, worker can informed other parts of program when has changed.

we need of in way allows use update ui safely

let's start observer...

public interface progresslistener {     public void progresschanged(double progress);     public void setstatus(string text); } 

pretty simple, notify when progress of status changes, allowing ever listening make updates see fit.

the basic progress value between 0-1, meaning listener doesn't care how many values have, cares progress, eliminates need try , update progress bar it's maximum value , instead, focus on need update progress bar between 0-100

now need make room in rest of api

private void converttoxls(filemanager filemgr, progresslistener listener) {     try {         int = 1;         listener.progresschanged(0d);         list<file> files = filemgr.getfiles(listener);         (file file : files) {             listener.setstatus("reading " + + " of " + filemgr.getsize() + " files");             parutils.parsefileusingdom(file); // read content of input file              listener.progresschanged(i / (double) files.size());         }         btnconvertxmlto.setenabled(true);      } catch (exception e) {         e.printstacktrace();     } } 

and filemanager#getfiles....

public list<file> getfiles(progresslistener listener) {     iterator = dirfiles.entryset().iterator();     int count = dirfiles.size();     (map.entry<string, arraylist<string>> entry : dirfiles.entryset()){         count += entry.getvalue() == null ? 0 : entry.getvalue().size();     }     int index = 0;     listener.setstatus("processing files...");     while (it.hasnext()) {         map.entry pair = (map.entry) it.next();         string foldername = (pair.getkey()).tostring();         arraylist<string> filenames = (arraylist<string>) pair.getvalue();         if (filenames != null) {             (string filename : filenames) {                 if (replaceselected(filename)) {                     file fxmlfile = new file(filename);                     files.add(fxmlfile);                 } else {                 }                 index++;                 listener.progresschanged(index / (double)count);             }         }     }     return files; } 

next, need update task take advantage of it's progress support, need allow ability change status of progress bar.

this can through publish/process methods, send messages background thread edt. can "cheat" little , use send messages change indeterminate state of progress bar (fyi: use property change listener support well, might cleaner approach)

class task extends swingworker<void, string> {      protected   static final string indeterminate_on = "indeterminate.on";     protected   static final string indeterminate_off = "indeterminate.off";      private filemanager filemgr;      public task(string srcpath) {         this.filemgr = new filemanager(new file(srcpath));      }      @override     protected void process(list<string> chunks) {         (string text : chunks) {             if (indeterminate_off.equals(text)) {                 progressbar.setindeterminate(false);             } else if (indeterminate_on.equals(text)) {                 progressbar.setindeterminate(true);             } else {                 progressbar.setstring(text);             }         }     }      /*          * main task. executed in background thread.      */     @override     public void doinbackground() {         try {             publish(indeterminate_on);             filemgr.readfiles();             publish(indeterminate_off);             converttoxls(filemgr, new progresslistener() {                 @override                 public void progresschanged(double progress) {                     setprogress((int) (progress * 100d));                 }                  @override                 public void setstatus(string text) {                     publish(text);                 }             });         } catch (exception e) {             e.printstacktrace();         }         return null;     }      /*          * executed in event dispatching thread      */     @override     public void done() {         toolkit.getdefaulttoolkit().beep();         try {             progressbar.setstring("fileread successful");         } catch (exception e) {             // todo auto-generated catch block             e.printstacktrace();         }     } }//end of task class 

and finally, need add propertychangelistener task when create it, can progress updates , update progress bar...

task.addpropertychangelistener(new propertychangelistener() {     @override     public void propertychange(propertychangeevent evt) {         string name = evt.getpropertyname();         switch (name) {             case "progress":                 int value = (int) evt.getnewvalue();                 progressbar.setvalue(value);                 break;         }     } }); 

simple :p


Comments

Popular posts from this blog

javascript - Chart.js (Radar Chart) different scaleLineColor for each scaleLine -

apache - Error with PHP mail(): Multiple or malformed newlines found in additional_header -

java - Android – MapFragment overlay button shadow, just like MyLocation button -