Ленивые изображения нагрузки на ListView в Android (уровень начинающего)? [Дубликат

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

Вопрос

Возможный дубликат:
Android - Как мне сделать ленивый загрузку изображений в ListView

Я работаю над ListView с пользовательским адаптером. Я хочу загрузить изображения и представление текста на нем. Изображения загружаются из URL-адреса интернет. Я просто хочу показать изображения, которые являются видимым списком элемента для пользователя HTE. Я сослал Полки Opensource Проект Пример из Romaingey, но это сложно понять код. Для новичка, я просто хочу знать, как обрабатывать тег между адаптером и активностью. Из Согласие пример Я могу установить тег на адаптере, но не могу показать соответствующее изображение в состоянии холостого состояния ListView. Пожалуйста, помогите мне с вашими идеями. Коды образцов более понятны.

Спасибо.

РЕДАКТИРОВАТЬ:

Комбинация Эффективный а также Медленный Адаптер в Apidemos более полезен для понимания.

Изменения, сделанные на эффективный пример адаптера, как это:

public class List14 extends ListActivity implements ListView.OnScrollListener {
// private TextView mStatus;

private static boolean mBusy = false;
static ViewHolder holder;

public static class EfficientAdapter extends BaseAdapter {
    private LayoutInflater mInflater;
    private Bitmap mIcon1;
    private Bitmap mIcon2;

    public EfficientAdapter(Context context) {
        // Cache the LayoutInflate to avoid asking for a new one each time.
        mInflater = LayoutInflater.from(context);

        // Icons bound to the rows.
        mIcon1 = BitmapFactory.decodeResource(context.getResources(),
                R.drawable.icon48x48_1);
        mIcon2 = BitmapFactory.decodeResource(context.getResources(),
                R.drawable.icon48x48_2);
    }

    /**
     * The number of items in the list is determined by the number of
     * speeches in our array.
     * 
     * @see android.widget.ListAdapter#getCount()
     */
    public int getCount() {
        return DATA.length;
    }

    /**
     * Since the data comes from an array, just returning the index is
     * sufficent to get at the data. If we were using a more complex data
     * structure, we would return whatever object represents one row in the
     * list.
     * 
     * @see android.widget.ListAdapter#getItem(int)
     */
    public Object getItem(int position) {
        return position;
    }

    /**
     * Use the array index as a unique id.
     * 
     * @see android.widget.ListAdapter#getItemId(int)
     */
    public long getItemId(int position) {
        return position;
    }

    /**
     * Make a view to hold each row.
     * 
     * @see android.widget.ListAdapter#getView(int, android.view.View,
     *      android.view.ViewGroup)
     */
    public View getView(int position, View convertView, ViewGroup parent) {
        // A ViewHolder keeps references to children views to avoid
        // unneccessary calls
        // to findViewById() on each row.

        // When convertView is not null, we can reuse it directly, there is
        // no need
        // to reinflate it. We only inflate a new View when the convertView
        // supplied
        // by ListView is null.
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.list_item_icon_text,
                    null);

            // Creates a ViewHolder and store references to the two children
            // views
            // we want to bind data to.
            holder = new ViewHolder();
            holder.text = (TextView) convertView.findViewById(R.id.text);
            holder.icon = (ImageView) convertView.findViewById(R.id.icon);

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

            // Null tag means the view has the correct data
            holder.icon.setTag(null);
        } else {
            holder.icon.setImageBitmap(mIcon2);

            // Non-null tag means the view still needs to load it's data
            holder.icon.setTag(this);
        }
        holder.text.setText(DATA[position]);

        // Bind the data efficiently with the holder.
        // holder.text.setText(DATA[position]);

        return convertView;
    }

    static class ViewHolder {
        TextView text;
        ImageView icon;
    }
}

private Bitmap mIcon1;
private Bitmap mIcon2;
@Override
public void onCreate(Bundle savedInstanceState) {
    mIcon1 = BitmapFactory.decodeResource(this.getResources(),
            R.drawable.icon48x48_1);
    mIcon2 = BitmapFactory.decodeResource(this.getResources(),
            R.drawable.icon48x48_2);
    super.onCreate(savedInstanceState);
    setListAdapter(new EfficientAdapter(this));
    getListView().setOnScrollListener(this);
}

public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {
}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    switch (scrollState) {
    case OnScrollListener.SCROLL_STATE_IDLE:
        mBusy = false;

        int first = view.getFirstVisiblePosition();
        int count = view.getChildCount();
        for (int i = 0; i < count; i++) {

            holder.icon = (ImageView) view.getChildAt(i).findViewById(
                    R.id.icon);
            if (holder.icon.getTag() != null) {
                holder.icon.setImageBitmap(mIcon1);
                holder.icon.setTag(null);
            } 
        }

        // mStatus.setText("Idle");
        break;
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
        mBusy = true;
        // mStatus.setText("Touch scroll");
        break;
    case OnScrollListener.SCROLL_STATE_FLING:
        mBusy = true;
        // mStatus.setText("Fling");
        break;
    }
}
private static final String[] DATA = { "Abbaye de Belloc",
        "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
        "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu"};
}

Сейчас работает нормально. Но когда состояние прокрутки это не перезагружает изображение правильно. Какой-то интервал предметов не показывает изображения2. Это правильный порядок изображений загружается. Но не во всех предметах списка. Несоответствия происходит между прочными интервалами. Как исправить это?

Это было полезно?

Решение

Praven -

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

Вот основное обсуждение:http://ballardhack.wordpress.com/2010/04/05/loading-remote-images-in-a-listview-on-android/

И есть класс, который я задокументировал позже, который использует нить и обратный вызов для загрузки изображений:

http://ballardhack.wordpress.com/2010/04/10/loading-images-ver-http-on-a-separate-thread-on-android/

Обновлять: Чтобы решить ваше конкретное исключение, я думаю, что этот взгляд возвращен в список из getChildAt не является ImageView - Это какой бы ни был просмотр макета, который вы используете, чтобы удерживать изображение и текст.

Обновление, чтобы включить соответствующий код: (Рекомендация за @ Джордж-стоковый вектор)

Вот адаптер, который я использовал:

public class MediaItemAdapter extends ArrayAdapter<MediaItem> {
  private final static String TAG = "MediaItemAdapter";
  private int resourceId = 0;
  private LayoutInflater inflater;
  private Context context;

  private ImageThreadLoader imageLoader = new ImageThreadLoader();

  public MediaItemAdapter(Context context, int resourceId, List<MediaItem> mediaItems) {
    super(context, 0, mediaItems);
    this.resourceId = resourceId;
    inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    this.context = context;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {

    View view;
    TextView textTitle;
    TextView textTimer;
    final ImageView image;

    view = inflater.inflate(resourceId, parent, false);

    try {
      textTitle = (TextView)view.findViewById(R.id.text);
      image = (ImageView)view.findViewById(R.id.icon);
    } catch( ClassCastException e ) {
      Log.e(TAG, "Your layout must provide an image and a text view with ID's icon and text.", e);
      throw e;
    }

    MediaItem item = getItem(position);
    Bitmap cachedImage = null;
    try {
      cachedImage = imageLoader.loadImage(item.thumbnail, new ImageLoadedListener() {
      public void imageLoaded(Bitmap imageBitmap) {
      image.setImageBitmap(imageBitmap);
      notifyDataSetChanged();                }
      });
    } catch (MalformedURLException e) {
      Log.e(TAG, "Bad remote image URL: " + item.thumbnail, e);
    }

    textTitle.setText(item.name);

    if( cachedImage != null ) {
      image.setImageBitmap(cachedImage);
    }

    return view;
  }
}

Другие советы

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

public class List14 extends ListActivity implements ListView.OnScrollListener {
// private TextView mStatus;

private static boolean mBusy = false;
static ViewHolder holder;

public static class EfficientAdapter extends BaseAdapter {
    private LayoutInflater mInflater;
    private Bitmap mIcon1;
    private Bitmap mIcon2;
    private Context mContext;

    public EfficientAdapter(Context context) {
        // Cache the LayoutInflate to avoid asking for a new one each time.
        mInflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mContext = context;
        // Icons bound to the rows.
        mIcon1 = BitmapFactory.decodeResource(context.getResources(),
                R.drawable.icon48x48_1);
        mIcon2 = BitmapFactory.decodeResource(context.getResources(),
                R.drawable.icon48x48_2);
    }

    /**
     * The number of items in the list is determined by the number of
     * speeches in our array.
     * 
     * @see android.widget.ListAdapter#getCount()
     */
    public int getCount() {
        return DATA.length;
    }

    /**
     * Since the data comes from an array, just returning the index is
     * sufficent to get at the data. If we were using a more complex data
     * structure, we would return whatever object represents one row in the
     * list.
     * 
     * @see android.widget.ListAdapter#getItem(int)
     */
    public Object getItem(int position) {
        return position;
    }

    /**
     * Use the array index as a unique id.
     * 
     * @see android.widget.ListAdapter#getItemId(int)
     */
    public long getItemId(int position) {
        return position;
    }

    /**
     * Make a view to hold each row.
     * 
     * @see android.widget.ListAdapter#getView(int, android.view.View,
     *      android.view.ViewGroup)
     */
    public View getView(int position, View convertView, ViewGroup parent) {
        // A ViewHolder keeps references to children views to avoid
        // unneccessary calls
        // to findViewById() on each row.

        // When convertView is not null, we can reuse it directly, there is
        // no need
        // to reinflate it. We only inflate a new View when the convertView
        // supplied
        // by ListView is null.
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.list_item_icon_text,
                    parent, false);

            // Creates a ViewHolder and store references to the two children
            // views
            // we want to bind data to.
            holder = new ViewHolder();
            holder.text = (TextView) convertView.findViewById(R.id.text);
            holder.icon = (ImageView) convertView.findViewById(R.id.icon);

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

        if (!mBusy) {

            holder.icon.setImageBitmap(mIcon1);

            // Null tag means the view has the correct data
            holder.icon.setTag(null);

        } else {
            holder.icon.setImageBitmap(mIcon2);

            // Non-null tag means the view still needs to load it's data
            holder.icon.setTag(this);
        }
        holder.text.setText(DATA[position]);

        // Bind the data efficiently with the holder.
        // holder.text.setText(DATA[position]);

        return convertView;
    }

    static class ViewHolder {
        TextView text;
        ImageView icon;
    }
}

private Bitmap mIcon1;
private Bitmap mIcon2;

@Override
public void onCreate(Bundle savedInstanceState) {
    mIcon1 = BitmapFactory.decodeResource(this.getResources(),
            R.drawable.icon48x48_1);
    mIcon2 = BitmapFactory.decodeResource(this.getResources(),
            R.drawable.icon48x48_2);
    super.onCreate(savedInstanceState);
    setListAdapter(new EfficientAdapter(this));
    getListView().setOnScrollListener(this);
}

public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {
}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    switch (scrollState) {
    case OnScrollListener.SCROLL_STATE_IDLE:
        mBusy = false;

        int first = view.getFirstVisiblePosition();
        int count = view.getChildCount();

        for (int i = 0; i < count; i++) {

            holder.icon = (ImageView) view.getChildAt(i).findViewById(
                    R.id.icon);
            if (holder.icon.getTag() != null) {
                holder.icon.setImageBitmap(IMAGE[first+i]);// this is the image url array.
                holder.icon.setTag(null);
            }
        }

        // mStatus.setText("Idle");
        break;
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
        mBusy = true;
        // mStatus.setText("Touch scroll");
        break;
    case OnScrollListener.SCROLL_STATE_FLING:
        mBusy = true;
        // mStatus.setText("Fling");
        break;
    }
}

private static final String[] DATA = { "Abbaye de Belloc",
        "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
        "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu",
        "Yarra Valley Pyramid", "Yorkshire Blue", "Zamorano",
        "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano" };
  }

Насколько я понимаю, вам нужно обновить свой список после завершения прокрутки. Это просто. Вот фиксированный код для вас:

EfficientAdapter adapter;

@Override
public void onCreate(Bundle savedInstanceState) {
    mIcon1 = BitmapFactory.decodeResource(this.getResources(),
            R.drawable.icon48x48_1);
    mIcon2 = BitmapFactory.decodeResource(this.getResources(),
            R.drawable.icon48x48_2);
    super.onCreate(savedInstanceState);
    adapter=new EfficientAdapter(this);
    setListAdapter(adapter);
    getListView().setOnScrollListener(this);
}

public void onScroll(AbsListView view, int firstVisibleItem,
    int visibleItemCount, int totalItemCount) {
}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    switch (scrollState) {
    case OnScrollListener.SCROLL_STATE_IDLE:
        mBusy = false;
        adapter.notifyDataSetChanged() 
        break;
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
        mBusy = true;
        // mStatus.setText("Touch scroll");
        break;
    case OnScrollListener.SCROLL_STATE_FLING:
        mBusy = true;
        // mStatus.setText("Fling");
        break;
    }
}

NotifyDataSethChanced, скажет адаптер, чтобы повторно отобразить все видимые элементы, поэтому они будут отображаться с изображением2.

Насколько я вижу, статический ViewHolder ничего не помогает. Попробуйте положить весь onScrollStateChanged функция между /* а также */, Удаление static ViewHolder линия и изменение holder = new ViewHolder(); к ViewHolder holder = new ViewHolder();.

Ах, проверьте логику, чтобы убедиться, что ваше приложение не будет убито и перезапущено. Большинство телефонов ограничивают общий размер приложения до 16 МБ или 24 МБ. Легко загрузить кучу изображений, запустите, погибнуть, перезагрузите, и у вас нет нагрузки не загружают большие данные выключения. Это бедная коллекция на гарабаре.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top