1

我在 ListView 中使用 AsyncTask 加载图像时遇到了这个奇怪的问题。在我的 ListView 中,每一行都包含一个 ImageView 和一个 TextView。我为它点击了这个链接:

http://android-developers.blogspot.in/2010/07/multithreading-for-performance.html

图像已从 URL 成功下载,并填充在其受尊重的行上。但是当我滚动 ListView 或单击任何列表项时,图像只会交换它们的行。尽管 TextViews 中的文本保持在同一行上。我不明白为什么会这样。我用谷歌搜索了很多,但找不到完美的理由。请帮忙。

这是我的适配器类:

     private class ListAdapter extends BaseAdapter{

    private ArrayList<HashMap<String, Object>> allFriends; 
    private LayoutInflater mInflater;

    public ListAdapter(ArrayList<HashMap<String, Object>> allFriends, Context context){
        this.allFriends = allFriends;
        mInflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return allFriends.size();
    }

    @Override
    public Object getItem(int position) {
        return allFriends.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        FriendsViewHolder holder;

        if (convertView == null||!(convertView instanceof TextView)||!(convertView instanceof ImageView)) {
             convertView = mInflater.inflate(R.layout.friend_list_view, null);

             holder = new FriendsViewHolder();
             holder.friendName = (TextView) convertView.findViewById(R.id.friendName);
             holder.friendImage = (ImageView) convertView.findViewById(R.id.friendImage);                

             convertView.setTag(holder);
         }else {
             holder = (FriendsViewHolder) convertView.getTag(); 
         }

        holder.friendName.setText((String) allFriends.get(position).get(FriendsActivity.FRIENDS_NAME_KEY));

        String otherId=(String) allFriends.get(position).get(FriendsActivity.IDKEY);
        String isImage=(String) allFriends.get(position).get(FriendsActivity.IS_IMAGE_KEY);

            if(isImage.equalsIgnoreCase("true")){
                download(otherId, holder.friendImage);
            }

        return convertView;
    }
}//End of list adapter

下载方法是:

   public void download(String otherId, ImageView imageView) {
     BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
     task.execute(otherId);
 }

这里的 BitmapDownloaderTask 是下载图片的异步任务:

    class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
        private String otherId;
        private final WeakReference<ImageView> imageViewReference;

        public BitmapDownloaderTask(ImageView imageView) {
            imageViewReference = new WeakReference<ImageView>(imageView);
        }

        @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 getOtherUserImage(params[0]);
        }

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

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

getOtherUserImage 方法是:

    public Bitmap getOtherUserImage(String otherUserId){

    // code to download the image goes here. It returns bitmap "bmImg".

    if(bmImg==null){
        return null;
    }else {
        bmImg = Bitmap.createScaledBitmap(bmImg,imageWidth, imageHeight, true);

        /*availableFriends.get(position).put(BITMAP_KEY, bmImg);
        runOnUiThread(new Runnable() {
            public void run() {
                adapter.notifyDataSetChanged();
            }
        });*/
        return bmImg;
    }
}
4

2 回答 2

1

这篇Android 开发者博客文章描述了如何正确地将图像异步加载到 ListView 中,并提供了一个很棒的示例应用程序,您应该能够快速轻松地修改(我做过)以满足您的需求。

实际上,出于内存效率的原因,ListView循环使用用户滚动时显示的视图。如果一个人抛出列表,一个给定的ImageView对象将被多次使用。每次显示时都会ImageView正确触发图像下载任务,最终会更改其图像。那么问题出在哪里?与大多数并行应用程序一样,关键问题在于顺序。在我们的例子中,不能保证下载任务会按照它们开始的顺序完成。结果是最终显示在列表中的图像可能来自上一个项目,只是碰巧下载的时间更长。如果您下载的图像一劳永逸地绑定到 given ,这不是问题 ImageViews

于 2012-07-28T19:56:16.110 回答
0

我认为您应该使下载图像的方法“同步”。许多线程同时运行,因此图像有可能出现在错误的位置。

于 2012-10-25T13:09:51.660 回答