【问题标题】:getView of ArrayAdapter inconsistent with image downloadingArrayAdapter的getView与图片下载不一致
【发布时间】:2011-12-26 05:14:12
【问题描述】:

我有从服务器下载图像的 GridView,我使用延迟加载方法将图像异步添加到网格。

我可以看到 getView 方法被多次调用,并且网格视图的位置不一致,直到图像被下载以获取位置。

现在,当我滚动 gridview 时,已经为位置下载的图像现在被其他图像替换。

但是在所有图片都下载好后,它工作正常。

我知道并阅读了之前关于 getView 调用不一致的帖子,但仍然无法解决问题。

`@Override public View getView(final int position, View convertView, 最终视图组视图组){ ViewHolder viewHolder;

    if (convertView == null) {
        convertView = layoutInflater.inflate(R.layout.ondemand_grid_item,
                null);

        viewHolder = new ViewHolder();
        viewHolder.title = ((TextView) convertView
                .findViewById(R.id.ondemand_grid_item_title));
        viewHolder.image = ((ImageView) convertView
                .findViewById(R.id.ondemand_grid_item_image));
        viewHolder.iconImage = ((ImageView) convertView
                .findViewById(R.id.on_demand_trailer_icon));
        viewHolder.showSelectedImage = (ImageView) convertView.findViewById(R.id.ondemand_grid_item_img);
        viewHolder.showSelectedImage.setVisibility(View.INVISIBLE);
        viewHolder.showSelectedImage.setSelected(true);
        viewHolder.seasonNumber = (TextView) convertView.findViewById(R.id.ondemand_grid_item_season);
        viewHolder.seasonNumber.setVisibility(View.INVISIBLE);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    final OnDemandItem onDemandItem = getItem(position);
    imageLoader.DisplayImage(onDemandItem.getPosterUrl(), viewHolder.image, onDemandItem.getGenrePlaceHolder());
    showHideTrailerIcon(viewHolder, onDemandItem);
    if (onDemandItem.getType() == AssetTypeEnum.SERIE) {
        if (onDemandItem.getSeasonNumber() != null && !"".equals(onDemandItem.getSeasonNumber())) {
            viewHolder.seasonNumber.setVisibility(View.VISIBLE);
            viewHolder.seasonNumber.setText("Seizoen " + onDemandItem.getSeasonNumber());
        }
    }
    viewHolder.title.setText(onDemandItem.getTitle());

    if (selectedOndemandItemId == onDemandItem.getId()) {
        convertView.findViewById(R.id.ondemand_grid_item_img).setVisibility(View.VISIBLE);
    } else {
        ImageView showSelectedImage = (ImageView) convertView.findViewById(R.id.ondemand_grid_item_img);
        if (showSelectedImage != null) {
            showSelectedImage.setVisibility(View.INVISIBLE);
        }
    }

    return convertView;
}`

其中:imageLoader.DisplayImage(onDemandItem.getPosterUrl(), viewHolder.image, onDemandItem.getGenrePlaceHolder()); 是图片异步下载方式

【问题讨论】:

  • 发布您的 getView 方法,当我们有更多信息时,我们可以为您提供更多帮助。许多事情可能是错误的。
  • 这听起来可能是由回收的视图和异步回调引起的。需要您的代码验证
  • @HandlerExploit 编辑了我的问题,并附上了 getView 方法
  • @Spidy : 是的,我想和你一样,请找到附加的 getView 代码

标签: android gridview android-arrayadapter


【解决方案1】:

我使用两个哈希图解决了这个问题。当视图呈现时,会制作一个包含项目以及相应的 convertView 对象的地图。您需要确保传入的 OnDemandItem 项上有一个唯一的 ID,该 ID 可用于键入 hashmap。

所以重新编写你的代码:

//class variables
private HashMap<String, ViewHolder> mapDemandItems = new HashMap<>();
private HashMap<String, View> mapConvertView = new HashMap<>();

public View getView(int position, View convertView, ViewGroup parent) {
OnDemandItem onDemandItem = getItem(position);
viewHolder = mapDemandItems.get(onDemandItem.getId());

if (viewHolder == null) {
    viewHolder = new ViewHolder();
    convertView = layoutInflater.inflate(R.layout.ondemand_grid_item,
            null);

    //set viewHolder values

    mapDemandItems.put(onDemandItem.getId(), viewHolder);
    mapConvertView.put(onDemandItem.getId(), convertView);
} else {
    return mapConvertView.get(onDemandItem.getId());
}

...

return convertView;

}

【讨论】:

    【解决方案2】:

    尝试将 setTag 方法与 imageview 一起使用,我的解决方案是这样的,在适配器的 getView 方法中,setTag 到正在加载的 imageview。

    viewHolder.image.setTag(onDemandItem.getPosterUrl()) imageLoader.DisplayImage(onDemandItem.getPosterUrl(), viewHolder.image, onDemandItem.getGenrePlaceHolder());

    在imageLoader类中,在将加载的位图附加到imageview之前,检查imageview的getTag和url是否传递给loader类。

    【讨论】:

    • 我发现这对于大量图像的异步下载以及将图像的位图附加到正确的视图来说是一个更好的实现
    【解决方案3】:

    我之前也遇到过同样的问题。这是我的伪代码解决方案(我使用 monodroid,所以不确定它在 java 中是如何工作的,但算法应该很清楚)

    public override View GetView (int position, View convertView, ViewGroup parent)
    {
       View v = convertView;
    
       int rev = 0;
       lock(imageSync){
         if(v == null){
            LayoutInflater vi = (LayoutInflater)Context.GetSystemService (Context.LayoutInflaterService);
            v = vi.Inflate (_textViewResourceId, null);
         }
    
         rev = Math.Random();
         v.Tag = rev;
       }
    
       ImageView im = (ImageView)v.FindViewById (R.Id.image_view);
       if (im != null) {
          im.SetImageResource(R.Drawable.loading);
          ImageLoader loader = GetLoader();
          loader.OnImageLoadedListener=delegate (Drawable image, int backRev){
                lock(imageSync){
                   if(((int)v.Tag) != backRev) return;
                   else im.SetImage(image);
                }
          };
          loader.LoadImage(imageUrl, rev);
       }
    }
    

    因此,每次适配器向我询问数据时,我都会用随机修订号标记视图。当我使用延迟加载时,我将这个数字传递给加载器,它会在加载过程中保留它。加载完成后,我比较加载器返回的当前视图修订版和修订版。如果它们相等,那没关系,我设置图像。如果不是,这意味着在加载期间用户滚动了我的 ListView (GridView) 并且当前视图是另一个视图,而不是请求图像进入视图的视图。如果我将图像设置到其中,我将用已弃用的图像替换图像,所以我只是忽略这种情况。

    【讨论】:

    • 是的..我会像你提到的那样试一试
    • 我尝试了@PVolan 建议的算法,它通过在加载图像时设置界面来工作,并使用 getView 方法附加回来。还面临延迟加载图像加载器类的问题,因为它在不同的线程上运行。但我解决了。
    猜你喜欢
    • 1970-01-01
    • 2021-02-05
    • 1970-01-01
    • 1970-01-01
    • 2012-09-06
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    • 2015-12-08
    相关资源
    最近更新 更多