0

I am trying to retrieve an image from the Internet using a thread, and I am using a Handler to display the image on the UI once the image has finished downloading. It works fine on the Nexus S with ICS, but using a Samsung running Android 2.1, the image never gets displayed on the screen!

Moreover, what is weird is that when I do step-by-step debugging with a breakpoint inside the thread where the image gets fetched from the INternet, the code runs fine and the image gets displayed, but when I put the breakpoint further down, outside the thread, where the code to actually update the UI is, the image does not get displayed, as if this code is never reached. Here is my code:

private Handler handler;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
    formatter.setMinimumFractionDigits(2);
    formatter.setMaximumFractionDigits(2);
    handler = new Handler();
    ...

The function that starts the image retrieval by using a worker thread:

private void retrieveImage() {
    DeviceInfo dv = new DeviceInfo(this);
    String uri = MerchantProAPI.GET_CLIENT_IMAGE_URL;
    uri += "?api_id=" + MerchantProAPI.API_ID;
    uri += "&merchantphone=" + dv.getPhoneNumber();
    uri += "&imei=" + dv.getDeviceId();
    uri += "&customerid=" + customerno;
    Thread thr = new Thread(null, new RetrieveImageWorker(uri), "RetrieveImage");
    thr.start();
}

The RetrieveImageWorker is a private class in the activity, and I use the handler initialized in the onCreate method to post and update an imageview with the new image downloaded:

private class RetrieveImageWorker implements Runnable {
    String uri;
    Bitmap bm;

    public RetrieveImageWorker(String uri) {
        this.uri = uri;
    }

    @Override
    public void run() {
        HttpClient client = new DefaultHttpClient();
        HttpGet request = new HttpGet(uri);
        try {
            HttpResponse response = client.execute(request);
            HttpEntity entity = response.getEntity();
            String contentType = entity.getContentType().getValue();
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            int halfScreen = metrics.widthPixels / 2;
            int photoWidth = halfScreen > 200 ? 200 : halfScreen;
            if (contentType.contains("image/jpeg") || contentType.contains("image/png") || contentType.contains("image/gif")) {
                bm = BitmapFactory.decodeStream(entity.getContent());
                if (bm.getWidth() > photoWidth)
                bm = Bitmap.createScaledBitmap(bm, photoWidth, Math.round((photoWidth*bm.getHeight())/bm.getWidth()), false);
            }
            handler.post(new NotifierImage(bm));
        } catch (Exception e) {
            handler.post(new Notifier(e.getMessage()));
        }
    }

}

Here is the NotifierImage thread used to receive the bitmap in order to update the UI:

private class NotifierImage implements Runnable {
    private Bitmap bm;

    public NotifierImage(Bitmap bm) {
        this.bm = bm;
    }

    @Override
    public void run() {
        if (this.bm != null) {
            updateDisplayPhoto(bm);
        }
    }

}

The updateDisplayPhoto just updates an imageview of the UI:

private void updateDisplayPhoto(Bitmap photo) {
    imageView.setImageBitmap(photo);
}

All of these above are part of the same Activity. Like I said, on the Nexus S with ICS, it works fine, but on a Samsung with Android 2.1-update, the image never gets updated in the UI. What did I do wrong?

sbruno74
  • 51
  • 1
  • 7

1 Answers1

0

Simply Simply use AsyncTask. Put your code to retrieve image in your doInBackground() and set the image to ImageView in your PostExecute(). Why to use Runnable and Thread if Android is providing a nice and clear way.

private class MyAsyncTask extends AsyncTask<Void, Void, Void>
    {
            @Override
        protected void onPreExecute() {
            mProgressDialog = ProgressDialog.show(ActivityName.this, "Loading...", "Data is Loading...");
        }

        @Override
        protected Void doInBackground(Void... params) {
           // your network operation
            return null;
        }
        ProgressDialog mProgressDialog;
        @Override
        protected void onPostExecute(Void result) {
            mProgressDialog.dismiss();
        }
    }
Lalit Poptani
  • 67,150
  • 23
  • 161
  • 242
  • The best is [this](http://developer.android.com/reference/android/os/AsyncTask.html) and for example – Lalit Poptani Jan 25 '12 at 05:36
  • And [here](http://stackoverflow.com/questions/8612406/android-os-networkonmainthreadexception-need-to-use-async-task/8612418#8612418) is an example how you can do it actually. – Lalit Poptani Jan 25 '12 at 05:39
  • i have url how to call this Asynctask with this url. – RajaReddy PolamReddy Jan 25 '12 at 05:57
  • You can pass url in parameter to AsyncTask. – Lalit Poptani Jan 25 '12 at 05:59
  • Thank you for your suggestion. I am used to AsyncTask and, in fact, I use it for other things in the same application. I have an entire web API built around AsyncTask. I am going to try to implement this using AsyncTask, but I am still curious to know why it does not work with this Handler example... just for pedagogical reasons... – sbruno74 Jan 25 '12 at 19:27