0

私は、ArrayAdapter を介して取り込まれているリストビューを持つアプリケーションに取り組んでいます。現在非常にいらいらしている問題を除いて、すべてが正常に機能しています。

私のリスト ビューには、画像とテキストを含むカスタム レイアウトが含まれています。問題は画像部分です。リストにデータが入力された後にリストをタップすると、リスト内の画像がその位置に入れ替わります。たとえば、1 番目のセルに関連付けられた画像は 3 番目のセルに移動し、その逆も同様です。画像でのみ発生します。テキストはその位置にとどまります。何が問題なのかわからない。この深刻な問題から私を助けてください。

以下は私のアダプターコードです:

 public class PListAdapter extends ArrayAdapter<Product> {

Context context;
ArrayList<Product> products;
LayoutInflater vi;
ProgressBar mSpinner;

private ImageView imageView;

public void setItems(ArrayList<Product> items) {
    this.products = items;
}

public ProductListAdapter(Context context, ArrayList<Product> productList) {
    super(context, 0, productList);
    // TODO Auto-generated constructor stub

    this.context = context;
    this.products = productList;

}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub

    View v = convertView;
    final Product p = products.get(position);

    if (p != null) {

        if (v == null) {

            vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.sample_singlerow, null);
        }

        imageView = (ImageView) v.findViewById(R.id.product_image);
        TextView title = (TextView) v.findViewById(R.id.product_title);
        TextView summary = (TextView) v.findViewById(R.id.product_summary);
        TextView price = (TextView) v.findViewById(R.id.product_price);
        TextView type = (TextView) v.findViewById(R.id.product_type);
        ImageView pImage = (ImageView) v.findViewById(R.id.persons);

        if (imageView != null) {
            if (p.getImage() == null) {
                if (p.getImageURL() != null) {

                    new AsyncImageLoader(imageView, p.getImageURL());

                }
            }
        }

        if (title != null) {
            Log.i("Title: ", p.getName());
            title.setText(p.getName());
        }

        if (summary != null) {

            Log.i("Summary: ", p.getDescription());
            summary.setText(p.getDescription().substring(0, 110) + "...");
        }

        if (price != null) {
            Log.i("Price: ", p.getPrice());
            price.setText(p.getPrice());
        }

        if (type != null) {
            Log.i("Type: ", p.getType());
            type.setText(p.getType() + " Person");
        }

        if (pImage != null) {

            try {

                if (p.getType().equals("1")) {

                    pImage.setImageResource(R.drawable.one_person);

                } else if (p.getType().equals("2")) {

                    pImage.setImageResource(R.drawable.two_person);

                }

            } catch (NotFoundException e) {
                // TODO Auto-generated catch block
                pImage.setImageDrawable(null);
                e.printStackTrace();
            }
        }

    }

    return v;
}

編集:

public class AsyncImageLoader { private final WeakReference imageViewReference;

public  AsyncImageLoader(ImageView imageView,String imageUrl) {
    imageViewReference = new WeakReference<ImageView>(imageView);
    String[] url={imageUrl};
    new BitmapDownloaderTask().execute(url);
}
// static int counter = 0;
// int imageNum = 0;

/**
 * This Interface in used by {@link AsyncImageLoader} to return a response
 * by after loading image
 */

public interface ImageCallback {
    public Drawable temp = null;

    /**
     * Load the Image in imageDrable, Image is loaded form imageUrl
     * 
     * @param imageDrawable
     *            Image in drawable format
     * @param imageUrl
     *            URL of image to be load
     */
    public void imageLoaded(Drawable imageDrawable, String imageUrl);
}

private String LOG_TAG;


class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
    private String url;


    @Override
    // Actual download method, run in the task thread
    protected Bitmap doInBackground(String... params) {
         // params comes from the execute() call: params[0] is the url.
         return downloadBitmap(params[0]);
    }

    @Override
    // Once the image is downloaded, associates it to the imageView
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (imageViewReference != null) {
            ImageView imageView = imageViewReference.get();
            if (imageView != null && !(bitmap==null)) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

Bitmap downloadBitmap(String url) {
    final int IO_BUFFER_SIZE = 4 * 1024;

    // AndroidHttpClient is not allowed to be used from the main thread
    final HttpClient client = AndroidHttpClient.newInstance("Android");
    final HttpGet getRequest = new HttpGet(url);

    try {
        HttpResponse response = client.execute(getRequest);
        final int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != HttpStatus.SC_OK) {
            Log.w("ImageDownloader", "Error " + statusCode +
                    " while retrieving bitmap from " + url);
            return null;
        }

        final HttpEntity entity = response.getEntity();
        if (entity != null) {
            InputStream inputStream = null;
            try {
                inputStream = entity.getContent();
                // return BitmapFactory.decodeStream(inputStream);
                // Bug on slow connections, fixed in future release.
                return BitmapFactory.decodeStream(new FlushedInputStream(inputStream));
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                entity.consumeContent();
            }
        }
    } catch (IOException e) {
        getRequest.abort();
        Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);
    } catch (IllegalStateException e) {
        getRequest.abort();
        Log.w(LOG_TAG, "Incorrect URL: " + url);
    } catch (Exception e) {
        getRequest.abort();
        Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);
    } finally {
        if ((client instanceof AndroidHttpClient)) {
            ((AndroidHttpClient) client).close();
        }
    }
    return null;
}
/*
 * An InputStream that skips the exact number of bytes provided, unless it reaches EOF.
 */
static class FlushedInputStream extends FilterInputStream {
    public FlushedInputStream(InputStream inputStream) {
        super(inputStream);
    }

    @Override
    public long skip(long n) throws IOException {
        long totalBytesSkipped = 0L;
        while (totalBytesSkipped < n) {
            long bytesSkipped = in.skip(n - totalBytesSkipped);
            if (bytesSkipped == 0L) {
                int b = read();
                if (b < 0) {
                    break;  // we reached EOF
                } else {
                    bytesSkipped = 1; // we read one byte
                }
            }
            totalBytesSkipped += bytesSkipped;
        }
        return totalBytesSkipped;
    }
}

}

何が問題なのか教えてください。お返事をお待ちしております。

4

2 に答える 2

0

ご覧のとおり、アダプターでのビューの再利用と非同期読み込みに問題があります。パフォーマンスとメモリを最適化するために、ビューを繰り返し膨張させるのではなく、Android はリスト アイテムを ListView のリサイクラーに「キャッシュ」しようとします。つまり、同じビュー (リスト アイテム) が毎回異なるデータ アイテムに対して数回使用されます。

その場合、既存のリストをスクロールするとどうなるかを確認してみましょう。一部のビューが膨張し、データが入力され、ImageView の画像のダウンロードが開始されます。別スレにて。

そして、前の Image が正常に読み込まれる前に、この View が別のデータ項目に再利用される場合はどうなるでしょうか? 現在、このイメージに対して新しい AsyncTask が開始されます。そして、競合状態が発生します。AsyncTask から結果がどの順序で返されるかは誰にもわかりません。

したがって、AsyncTask をビュー (タグなど) と共に保存するか、ハッシュマップを作成することをお勧めします。主な目的 - ビットマップの読み込みがいつ完了するかを判断する - この画像が別のビットマップ要求に使用されたかどうか。

このアプローチにより、imageViews が別のアイテムの間違った画像を表示するのを防ぐことができます。

それが役立つことを願っています、幸運を祈ります

于 2012-09-02T16:55:58.120 に答える