Веб-изображение загружено потоком в Android - PullRequest
2 голосов
/ 02 июня 2010

У меня расширенный BaseAdapter в ListActivity:

private static class RequestAdapter extends BaseAdapter {

и некоторые обработчики и исполняемые файлы, определенные в нем

// Need handler for callbacks to the UI thread
    final Handler mHandler = new Handler();

    // Create runnable for posting
    final Runnable mUpdateResults = new Runnable() {
        public void run() {
            loadAvatar();
        }
    };

    protected static void loadAvatar() {
        // TODO Auto-generated method stub
        //ava.setImageBitmap(getImageBitmap("URL"+pic));
        buddyIcon.setImageBitmap(avatar);
    }

В функции getView адаптера я получаю вид, подобный этому:

if (convertView == null) {
            convertView = mInflater.inflate(R.layout.messageitem, null);

            // Creates a ViewHolder and store references to the two children views
            // we want to bind data to.
            holder = new ViewHolder();
            holder.username = (TextView) convertView.findViewById(R.id.username);
            holder.date = (TextView) convertView.findViewById(R.id.dateValue);
            holder.time = (TextView) convertView.findViewById(R.id.timeValue);
            holder.notType = (TextView) convertView.findViewById(R.id.notType);
            holder.newMsg = (ImageView) convertView.findViewById(R.id.newMsg);
            holder.realUsername = (TextView) convertView.findViewById(R.id.realUsername);
            holder.replied = (ImageView) convertView.findViewById(R.id.replied);
            holder.msgID = (TextView) convertView.findViewById(R.id.msgID_fr);
            holder.avatar = (ImageView) convertView.findViewById(R.id.buddyIcon);
            holder.msgPreview = (TextView) convertView.findViewById(R.id.msgPreview);


            convertView.setTag(holder);
        } else {
            // Get the ViewHolder back to get fast access to the TextView
            // and the ImageView.
            holder = (ViewHolder) convertView.getTag();
        }

и изображение загружается следующим образом:

Thread sepThread = new Thread() {
                    public void run() {
                        String ava;
                        ava = request[8].replace(".", "_micro.");
                        Log.e("ava thread",ava+", username: "+request[0]);
                        avatar = getImageBitmap(URL+ava);
                        buddyIcon = holder.avatar;
                        mHandler.post(mUpdateResults);
                        //holder.avatar.setImageBitmap(getImageBitmap(URL+ava));
                    }
                };
                sepThread.start();

Теперь проблема, с которой я столкнулся, заключается в том, что если есть еще элементы, которые должны отображать одно и то же изображение, отображаются не все эти изображения. Когда вы прокручиваете список вверх и вниз, возможно, вы заполняете их все.

Когда я пробовал закомментированную строку (holder.avatar.setImageBitmap ...), приложение иногда принудительно закрывалось "только поток, создавший представление, может запросить ...". Но только иногда.

Есть идеи, как я могу это исправить? Любой из вариантов.

Ответы [ 3 ]

1 голос
/ 02 июня 2010

Когда вызывается getView, у вас есть аватар ImageView. Вы должны передать этот экземпляр в sepThread, а sepThread должен передать этот экземпляр в mUpdateResults. Таким образом, растровое изображение будет отображаться точно в том виде, для которого оно было загружено. В противном случае растровое изображение отображается на некоторый экземпляр budddyIcon, который является неправильным. Ваш поток загружал изображение в течение некоторого времени, и когда он готов, budddyIcon ссылается на другой ImageView, потому что другой getView уже был вызван.

Должно выглядеть примерно так:

public View getView(...){
  //skip
  (new SepThread(holder.avatar)).start();
}

public class SepThread extends Thread() {
    ImageView imageView;
    public SepThread(ImageVIew iv){
      imageView=iv;
    }
    public void run() {
        //skip
        Bitmap avatar = getImageBitmap(URL+ava);
        mHandler.post(new UpdateResults(imageView, avatar));
    }
};

class UpdateResults extends Runnable() {
  ImageView imageView;
  Bitmap bitmap;
  public UpdateResults(ImageView iv, Bitmap b){
    imageView=iv;
    bitmap=b;
  }
  public void run() {
      loadAvatar(imageView, bitmap);
  }
};

protected static void loadAvatar(ImageView iv, Bitmap b) {
    iv.setImageBitmap(b);
}

И, конечно, вы должны быть осведомлены о переработанных конвертах, как сказано выше.

Я сделал полный пример LazyList и опубликовал источник, также может быть полезным Ленивая загрузка изображений в ListView .

1 голос
/ 07 мая 2011

есть эта замечательная библиотека, ребята, для загрузки / кэширования изображений из Интернета https://github.com/koush/UrlImageViewHelper

просто поместите изображение и URL, и все готово =)

1 голос
/ 02 июня 2010

Так что вы не должны пытаться добавить изображение к представлению в другом потоке. Мой совет - использовать AsyncTask примерно так:

class GetImageTask extends AsyncTask<String, int[], Bitmap> {

    @Override
    protected Bitmap doInBackground(String... params) {
      Bitmap bitmap = null;

      // Get your image bitmap here

      return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmapResult) {
      super.onPostExecute(bitmapResult);
      // Add your image to your view
      holder.avatar.setImageBitmap(bitmapResult);
    }
}

Вы называете AsyncTask как:

new GetImageTask().execute(param1, param2, etc);

Для получения дополнительной информации об AsyncTask посмотрите: http://developer.android.com/reference/android/os/AsyncTask.html

...