Domanda

  

Eventuali duplicati:
   Android - Come faccio a fare un pigro carico di immagini in ListView

Sto lavorando sul listview con l'adattatore personalizzato. Voglio caricare le immagini e visualizzare testo su di esso. Le immagini sono di carico dai URL Internet. Voglio solo mostrare le immagini che sono elenco elemento visibile all'utente HTE. I riferiti al Ripiani opensource esempio di progetto da romainguy , ma la sua al complicato da capire il codice. Per un livello di principiante, voglio solo sapere come gestire il tag tra l'adattatore e l'attività. Dal commonsware esempio posso impostare il tag sull'adattatore, ma non può mostrare l'immagine corrispondente allo stato di inattività della listview. Please help me con le vostre idee. codici di esempio sono più comprensibili.

Grazie.

EDIT:

La combinazione di efficiente e lento adattatore in ApiDemos è più utile per capire.

i cambiamenti fatti sulla esempio adattatore efficiente in questo modo:

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

Funziona bene ora. Ma quando lo stato di scorrimento la sua non ricaricare l'immagine correttamente. certo intervallo di articoli non mostra l'images2. cioè l'ordine corretto delle immagini sono carico. Ma non in tutte le voci di elenco. Disallineamenti che accadono tra gli intervalli di voce solidi. come correggerlo?

È stato utile?

Soluzione

Praveen -

Come già trovato il mio blog post su questo, volevo solo spingere di nuovo a StackOverflow modo che altri possano utilizzarlo.

Ecco la discussione di base: http: // ballardhack. wordpress.com/2010/04/05/loading-remote-images-in-a-listview-on-android/

E c'è una classe ho documentato in seguito che utilizza un filo e un callback per caricare le immagini:

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

Aggiornamento: Per affrontare la vostra specifica eccezione, penso che vista tornato nella lista da getChildAt non è un ImageView - è tutto ciò visualizzazione layout si utilizza per contenere l'immagine e il testo.

Aggiornamento per includere relativo codice : (Per @ raccomandazione di george-Stocker)

Questa è l'adattatore che stavo usando:

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

Altri suggerimenti

I got it. Questo è il codice perfetto che voglio. Caricamento pigro lavora per adattatore personalizzato solo le icone elenco di questo elemento visibile. Speranza che aiuta i principianti

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

quanto ho capito è necessario aggiornare l'elenco dopo lo scorrimento è finito. Questo è facile. Ecco il codice fisso per voi:

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

notifyDataSetChanged dirà l'adattatore alla ri-visualizzare tutti gli elementi visibili, in modo da essere visualizzati con image2.

Per quanto posso vedere, la ViewHolder statico è non aiutare niente. Prova a mettere l'intera funzione onScrollStateChanged tra /* e */, rimuovendo la linea static ViewHolder, e cambiando holder = new ViewHolder(); a ViewHolder holder = new ViewHolder();.

Ah, controllare il logcat per assicurarsi che la vostra applicazione non viene ucciso e riavviato. La maggior parte dei telefoni limitano la dimensione totale applicazione per 16 MB o 24 MB. E 'facile da caricare su un mazzo di immagini, investito, farsi ammazzare, riavvio, e avere il vostro onPause non caricare dati di grandi dimensioni fuori dallo schermo. E 'la raccolta garabage poveri.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top