title: Android: async loaded bitmaps randomly don't appear in ImageView after ImageView.setBitmapDrawable(..)
body: <p>I have a ListView whose elements are photos I need to load from a remote API which I'm using loopj to access.</p>
  
  <p>After loopj downloads the photo data, I use an AsyncTask to process the data into a scaled bitmap.</p>
  
  <p>This usually works great, however.. </p>
  
  <p><strong>The problem</strong> </p>
  
  <p>In my AsyncTask's onPostExecute method, I call setImageBitmap on the ImageView. Occasionally, the bitmap simply doesn't appear in the ImageView after ImageView.setImageBitmap is called. I have verified through logs and also the debugger that ImageView.setImageBitmap is indeed called on the offending ImageView.</p>
  
  <p>If I scroll the list a bit, the list element redraws, and the image is loaded from memory cache and correctly appears on the ImageView. </p>
  
  <p>Here's my code:</p>
  
  <pre><code>public void setPersonImage(final ImageView personImageView, final Person p) {
      personImageView.setImageResource(R.drawable.empty_image);
  
      //kills unecessary requests for the imageview's previous occupant photo
      if(personImageView.getTag() != null) {
          AsyncHttpClient client = mPhotoRequestsMap.get(p.getEmployeeId());
          if(client != null) {
              client.cancelRequests(getActivity().getApplicationContext(), true);
              Log.d(TAG, "Cancled photo request for " + String.valueOf(p.getEmployeeId()));
          }
      }
  
      personImageView.setTag(p.getEmployeeId());
  
      //first attempt to grab photo from cache
      Bitmap cachedBitmap = mMemoryCache.get(p.getPhotoCacheKey());
      if(cachedBitmap != null) {
          personImageView.setImageBitmap(cachedBitmap);
          Log.d(TAG, "bitmap for " + String.valueOf(p.getEmployeeId()) + " retrieved from memory cache");
      } else {
  
          AsyncHttpClient client = ApiWrapper.getPersonImage(180,mUserSession, 
              getActivity().getApplicationContext(), p.getEmployeeId(),
              new MyAsyncHttpResponseHandler(this) {
                 @Override
                 public void onSuccess(String response) {
                      if(personImageView.getTag().equals(p.getEmployeeId())) {
                          // use async task to process the bitmap off the UI thread
                          AsyncTask&lt;String,Integer,Bitmap&gt; task = new AsyncTask&lt;String,Integer,Bitmap&gt;() {
                              @Override
                              protected Bitmap doInBackground(String... params) {
                                  String response = params[0];
                                  byte[] bitmapBytes = ApiWrapper.processImageResponse(response);
                                  Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
                                  Bitmap bmpScaled = ThumbnailUtils.extractThumbnail(bitmap, 180, 180);
                                  return bmpScaled;
                              }
  
                              protected void onPostExecute(Bitmap bitmap) {
                                  //set on imageview if tags agree 
                                  if(personImageView.getTag().equals(p.getEmployeeId())) {
                                      Log.d(TAG, "setting image view for " + p.getEmployeeId());
                                      personImageView.setImageBitmap(bitmap);
                                      mMemoryCache.put(p.getPhotoCacheKey(), bitmap);
  
                                  }
                                  else {
                                      Log.d(TAG, "tags don't match after decode bitmap, discarding...");
                                  }
                              }
  
                          };
  
                          task.execute(response);
                      }
                      else {
                          Log.d(TAG, "tags don't match BEFORE decode bitmap employee id: " + p.getEmployeeId() + " tag: " + personImageView.getTag());
                      }
                 }
  
  
             }
          );
  
          //create entry in PhotoRequestsMap table
          mPhotoRequestsMap.put(p.getEmployeeId(), client);
  
      } // end if not in cache
  }
  </code></pre>
  
  <p>I've tried calling invalidate() on the ImageView after the bitmap is set on it, but sadly that doesn't solve it.. </p>
  
  <p>I'd greatly appreciate any help or pointers. </p>
  
  <p><strong>Update</strong></p>
  
  <p>The getView method from my Adapter:</p>
  
  <pre><code>public View getView(int position, View convertView, ViewGroup parent) {
  
              // If we weren't given a view, inflate one
              if (convertView == null) {
                 convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_person, null);
              }
  
              Person p = getItem(position);
  
              TextView nameTextView = (TextView)convertView.findViewById(R.id.person_ListItemNameTextView);
              nameTextView.setText(p.getFirstName() + " " + p.getLastName());
  
              TextView idTextView = (TextView)convertView.findViewById(R.id.person_ListItemIdTextView);
              idTextView.setText(String.valueOf(p.getEmployeeId()));
  
              ImageView personImageView = (ImageView)convertView.findViewById(R.id.person_ListItemImageView);
              setPersonImage(personImageView, p);
  
              return convertView;
          }
  </code></pre>