2

I have a ListView whose elements are photos I need to load from a remote API which I'm using loopj to access.

After loopj downloads the photo data, I use an AsyncTask to process the data into a scaled bitmap.

This usually works great, however..

The problem

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.

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.

Here's my 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<String,Integer,Bitmap> task = new AsyncTask<String,Integer,Bitmap>() {
                            @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
}

I've tried calling invalidate() on the ImageView after the bitmap is set on it, but sadly that doesn't solve it..

I'd greatly appreciate any help or pointers.

Update

The getView method from my Adapter:

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;
        }
4

1 回答 1

1

我认为该.setImageBitmap(Bitmap)方法运行良好,您只需将其设置为null.

检查中的bitmap == null情况onPostExecute(Bitmap bitmap)。这也符合您在滚动时出现图像的观察,因为当时 AndroidgetView(..)再次调用可见行。

于 2014-01-24T21:07:33.273 回答