Bind the progress of a query to a progressProperty

2019-09-10 09:07发布

问题:

I got an app that upload and download images to a mysql database but this take like 5 secs and i want to tell the user the progress of this

i do the transactions in a task here is the code

            // progres bar indefinit 
            progressBar.setProgress(-1);
            Task<Void> task = new Task<Void>() {
                @Override
                protected Void call() throws Exception {
                  try {
                    //i net to put to sleep the javafx thread for making a connection
                    Thread.sleep(10);
                  } catch (InterruptedException ex) {
                      ex.printStackTrace();
                  }

                    Platform.runLater(new Runnable(){
                        public void run(){
                            //Coneccts to the data base
                            try(Connection conexionInterna = dbConn.conectarBD()) {
                            //Get the object from the data base 
                            rayosVacio = imagenrayos.cargaSolaUnResultado(nuevo.getId_rayos(), conexionInterna);
                            if (rayosVacio!=null) {
                                //sets the image if exists
                                imageView.setImage(rayosVacio.getIma__imaRay());
                            }else
                                //sets the defauld image
                                imageView.setImage(Nohay);
                            } catch (SQLException e) {
                              e.printStackTrace();
                            }

                            }
                    }); 
                  return null;
                }

            };

            task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
              @Override
              public void handle(WorkerStateEvent event) {
                //sets the progress bar in the final to complete
                progressBar.setProgress(100);
              }
            });

            Thread tt = new Thread(task);
            tt.setDaemon(false);
            tt.start();

with that code i make a intermittent progressBar but this is not what i looking for, looking to have the best UX i think the best is for demonstrate the progress

to do this it i think i have to know how many bytes are been transferred for the database to the pc but i dont know how to obtain this information

here is how i download images from the database

    public imagenrayos cargaSolaUnResultado(String dato, Connection conex){
        imagenrayos im = null; 
        String sqlSt = "SELECT `id_imaRay`,\n" +
                        "`ima__imaRay`,\n" +
                        "`id_rayos` \n"+
                        "FROM imagenrayos\n" +
                       "WHERE id_rayos = '"+dato+"';";
        try(PreparedStatement stta = conex.prepareStatement(sqlSt);
            ResultSet res = stta.executeQuery()){
            if (res.next()) {
                byte[] data = res.getBytes("ima__imaRay");
                BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));
                Image image = SwingFXUtils.toFXImage(img, null);
                im = new imagenrayos(  res.getString   ("id_imaRay"),
                                    image, 
                                    res.getString   ("id_rayos"));
            }
       } catch (SQLException | IOException ex) {
            ex.printStackTrace();
       }
    return im;
   }

with this i believe i can obtain the size of image an set my 100% target

byte[] data = res.getBytes("ima__imaRay");
int sizeofImage = data.length;

but here is my doubt, how to track the progress of the data transferred? this is the way or there are better options for making the information available for the user ?

EDIT

I found a way in Android to do this but i don't see how to implement in my case here is the Android Solution

class DownloadFileAsync extends AsyncTask<String, String, String> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        showDialog(DIALOG_DOWNLOAD_PROGRESS);
    }

    @Override
    protected String doInBackground(String... aurl) {
        int count;

    try {

    URL url = new URL(aurl[0]);
    URLConnection conexion = url.openConnection();
    conexion.connect();

    int lenghtOfFile = conexion.getContentLength();
    Log.d("ANDRO_ASYNC", "Lenght of file: " + lenghtOfFile);

    InputStream input = new BufferedInputStream(url.openStream());
    OutputStream output = new FileOutputStream("/sdcard/some_photo_from_gdansk_poland.jpg");

    byte data[] = new byte[1024];

    long total = 0;

        while ((count = input.read(data)) != -1) {
            total += count;
            publishProgress(""+(int)((total*100)/lenghtOfFile));
            output.write(data, 0, count);
        }

        output.flush();
        output.close();
        input.close();
    } catch (Exception e) {}
    return null;

    }
    protected void onProgressUpdate(String... progress) {
         Log.d("ANDRO_ASYNC",progress[0]);
         mProgressDialog.setProgress(Integer.parseInt(progress[0]));
    }

    @Override
    protected void onPostExecute(String unused) {
        dismissDialog(DIALOG_DOWNLOAD_PROGRESS);
    }
}
}

the key here will be how to put the progress of the SQL query inside of a while and there use the updateProgress(); method of task to bind this value to the progressProperty of the progressBar in something like this

progressBar.progressProperty().bind(task.progressProperty()); 

回答1:

Normally this is as simple as loading the image from a url in the background and tracking it's progress by binding the progress property of the progress bar to the progress property of the image. That would replicate the functionality of the Android code you posted with much less code.

ProgressBar bar = new ProgressBar();
Image image = new Image(url, true);
bar.progressProperty().bind(image.progressProperty());

The only tricky thing here is that the non-Android code you posted is not the same as the Android code in functionality. Instead of retrieving an image from a URL, the non-Android code is retrieving the image from a database.

If you want to monitor progress of retrieval of images stored in a database, then you need to do a few extra things:

  1. In an additional field in the database store the size of the image.
  2. Store the image itself in a Blob in the database.
  3. Retrieve the total size of the image from the database when required.
  4. Retrieve the Blob from the database as a stream.
  5. Register a custom URL protocol which is able to get the database stream and convert the stream to a URL. (Alternately you could host a web application servlet which does the conversion and returns the data over http).
  6. Now you can load the image in the background using your custom URL protocol and monitor its progress via its progress property as before.

Doing step 5 is tricky and I will not write the code to do it here as creating such code would take me a long time.