官术网_书友最值得收藏!

Providing deterministic progress feedback

Knowing that something is happening is a great relief to our users, but they might be getting impatient and wondering how much longer they need to wait. Let's show them how we're getting on by adding a progress bar to our dialog.

Remember that we aren't allowed to update the user interface directly from doInBackground(), because we aren't on the main thread. How, then, can we tell the main thread to make these updates for us?

AsyncTask comes with a handy callback method for this, whose signature we saw at the beginning of the chapter:

protected void onProgressUpdate(Progress... values)

We can override onProgressUpdate() to update the user interface from the main thread, but when does it get called and where does it get its Progress... values from? The glue between doInBackground() and onProgressUpdate() is another of AsyncTask's methods:

   protected final void publishProgress(Progress... values)

To update the user interface with our progress, we simply publish progress updates from the background thread by invoking publishProgress() from within doInBackground(). Each time we call publishProgress(), the main thread will be scheduled to invoke onProgressUpdate() for us with these progress values.

The modifications to our running example to show a deterministic progress bar are quite simple. Since we have already defined the DownloadImageTask Progress type as Integer, now, we must change the setting progress values in the range 0 (setProgress) to 100 (setMax) and set the style and the bounds of the progress bar. We can do that with the following additions to onPreExecute():

@Override
protected void onPreExecute() {
    ...
    // Sets the progress bar style
    progress.setProgressStyle(
        ProgressDialog.STYLE_HORIZONTAL);
    progress.setIndeterminate(false);
    progress.setProgress(0);
    progress.setMax(100);
    progress.setCancelable(false);
    progress.show(); 
}

We also need to implement the onProgressUpdate callback to update the progress bar from the main thread:

@Override
protected void onProgressUpdate(Integer... values) {
  progress.setProgress(values[0]);
  }

The final modification is to calculate the progress at each iteration of the for loop, and invoke publishProgress() so that the main thread knows to call back onProgressUpdate():

private Bitmap downloadBitmap(URL url) {
  InputStream is = null;
  ...
  // Before Download starts
  publishProgress(0);
  downloadedBytes = 0;
  // Creates a Connection to the image URL
  HttpURLConnection conn = (HttpURLConnection) url.
                             openConnection();
  ...
  // Retrieves the image total length
  totalBytes = conn.getContentLength();
    ...
  BufferedInputStream bif = new BufferedInputStream(is) {

    int progress = 0;

      public int read(byte[] buffer, int byteOffset,
                      int byteCount) throws IOException {      
        // The number of bytes read in each stream read
      int readBytes = super.read(buffer, byteOffset,
                                 byteCount);
      ..
      // Actual number of bytes read from the file
      downloadedBytes += readBytes;
      // Percent of work done
      int percent = (int)((downloadedBytes * 100f) /
                      totalBytes);
      // Publish the progress to the main thread
      if (percent > progress) {
        publishProgress(percent);
        progress = percent;
      }     
  ...
}

It is important to understand that invoking publishProgress() does not directly invoke the main thread, but adds a task to the main thread's queue, which will be processed at some time in the near future by the main thread.

Notice that we're being careful to publish progress only when the percentage actually changes, avoiding any unnecessary overhead:

Note

Is important to know that every time you invoke publishProgress() on the background thread, in downloadBitmat(), a new Handler message is sent automatically internally to push the progress to the main thread.

Figure 3.4: Deterministic Progress Dialog showing the task progress

As can be seen in Figure 3.4, the deterministic dialog created in onPreExecute() is updated continuously in doInBackground() with the current progress of the task. The progress is calculated as a ratio, as in the following division:

The delay between publishing the progress and seeing the user interface update will be extremely short for this example and for any application that doesn't have too much UI work to process. The progress bar will update smoothly following the golden rule of not blocking the main thread for any of our code, since we only dispatch a progress update when the percentage changes.

主站蜘蛛池模板: 会泽县| 山阴县| 韶关市| 东乡县| 苍山县| 三台县| 加查县| 神木县| 南丹县| 常宁市| 三亚市| 淮滨县| 堆龙德庆县| 金山区| 泰兴市| 阿拉善盟| 通州区| 都江堰市| 寿光市| 丰台区| 贞丰县| 双鸭山市| 安岳县| 榆树市| 攀枝花市| 抚松县| 太康县| 建宁县| 神农架林区| 满城县| 当阳市| 罗平县| 高邑县| 奉化市| 新巴尔虎右旗| 大英县| 江永县| 汉川市| 东阿县| 东乡县| 泽州县|