How can I prevent images in this Android listview from shifting around when I click on other screen elements?

StackOverflow https://stackoverflow.com/questions/4287412

문제

I made another post earlier about this subject but I've since changed my code around a bit based on suggestions but the same problem exists. My images keep shifting around if I click other elements on screen.

Here is my code which I call by this:

new Thumbnailer(image_main, image_table).execute(image);

image_main is my imageView and image_table is the table that holds it.

 private class Thumbnailer extends AsyncTask<String, Void, Bitmap> {
      private ImageView imageView;
      private TableLayout imageTable;

        public Thumbnailer(ImageView imageView, TableLayout imageTable) {
            this.imageView = imageView;
            this.imageTable = imageTable;
        }

  @Override
  protected void onPostExecute(Bitmap result) {
      imageView.setImageBitmap(result);
               imageView.setVisibility(View.VISIBLE);
               imageTable.setVisibility(View.VISIBLE);
  }
  @Override
      protected void onProgressUpdate(Void... progress) {
      }

  @Override
  protected Bitmap doInBackground(String... params) {
         BitmapFactory.Options o = new BitmapFactory.Options();
          o.inJustDecodeBounds = true;
          BitmapFactory.decodeFile(params[0], o);
          final int REQUIRED_SIZE=70;

          //Find the correct scale value. It should be the power of 2.
          int width_tmp=o.outWidth, height_tmp=o.outHeight;
          int scale=1;
          while(true){
              if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                  break;
              width_tmp/=2;
              height_tmp/=2;
              scale++;
          }
          //Decode with inSampleSize
          BitmapFactory.Options o2 = new BitmapFactory.Options();
          o2.inSampleSize=scale;       
          return BitmapFactory.decodeFile(params[0], o2);
  }
 }
도움이 되었습니까?

해결책

Sounds like you're getting bitten by view recycling. That is, when you scroll a List in Android, it doesn't create a new row and instead reuses a row taken offscreen. In this case, that can result in multiple tasks trying to load an image into a single imageview. You effectively need to somehow be able to tell which load request is the most recent for a row and cancel the earlier ones/ignore their results, or just use a library that handles this for you (like droid-fu).

You could also just turn off view recycling in your Adapter (that's the part that uses the convertView argument in the getView method), but be aware this will make list scrolling slow and jittery, especially on older devices.

다른 팁

I had a similar problem. I would load images into a ListView via an AsyncTask (which might fetch the image via HTTP), and it seemed to load the wrong image for a split second before loading the correct one. It was as if Android was reusing the row before the HTTP request finished, and the AsyncTasks were kind of colliding.

The comments above confirmed that is what was happening.

I fixed it by placing the image path in the tag of the ImageView before the AsyncTask starts, and then checking that tag after the AsyncTask finishes but just before it calls setImageBitmap.

Add these lines:

final String somethingUnique = "put the image path or some other identifier here";
image_main.setTag(somethingUnique);

Before this line:

new Thumbnailer(image_main, image_table).execute(image);

Now, in onPostExecute, check the tag:

// if this does not match, then the view has probably been reused
if (((String)imageView.getTag()).equals(somethingUnique)) {
  imageView.setImageBitmap(result);
}

This Android Developer's blog post provides a reference project for this. Just change the http image download code in the project to your doInBackground code.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top