滚动列表时视图意外更改

Posted

技术标签:

【中文标题】滚动列表时视图意外更改【英文标题】:view changed unexpectedly when scroll list 【发布时间】:2014-01-18 21:55:40 【问题描述】:

我在膨胀列表视图时遇到了一个意想不到的问题。

我正在创建一个列表视图,其中显示图像标题和缩略图。我们还可以显示音频文件的缩略图,但只提供图像类。

当我快速滚动列表时。它的观点改变了很多次。在我使用 AsynkTask 类获取缩略图并将此缩略图设置为 imageview 的适配器类下方。

public class AdapterForBooks extends ArrayAdapter<ModelFile> 

    List<ModelFile> list;
    Context context;
    WindowManager wm;
    Display display;
    int w;

    public AdapterForBooks(Context context, List<ModelFile> list) 
        super(context, R.layout.list_layout_home, list);
        // TODO Auto-generated constructor stub
        this.list = list;
        this.context = context;
        wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        display = wm.getDefaultDisplay();
        w = display.getWidth();

    

    static class ViewHolder 
        TextView txtName;
        ImageView img;
    

    @Override
    public View getView(int position, View convertView, ViewGroup parent) 
        // TODO Auto-generated method stub
        View view = null;
        if (convertView == null) 
            LayoutInflater inflter = (LayoutInflater) LayoutInflater
                    .from(context);
            view = inflter.inflate(R.layout.list_layout_home, null);
            final ViewHolder holder = new ViewHolder();
            holder.txtName = (TextView) view
                    .findViewById(R.id.textViewName);
            holder.img = (ImageView) view.findViewById(R.id.imageView);
            LayoutParams params = (LayoutParams) holder.img
                    .getLayoutParams();
            params.height = w / 4;
            params.width = w / 4;
            holder.img.setLayoutParams(params);
            view.setTag(holder);
         else 
            view = convertView;
        
        final ViewHolder holder = (ViewHolder) view.getTag();
        String name = list.get(position).getFileName();
        holder.txtName.setText(name);

        String filePath = list.get(position).getFilePath();
        // holder.img.setImageBitmap(Bitmap.createScaledBitmap(BitmapFactory.decodeFile(filePath),100,100,false));
        new SetThumbnail()
                .execute(new Thumbnail(holder, filePath, position));
        return view;
    

    class Thumbnail 
        ViewHolder holder;
        String path;
        int position;

        public Thumbnail(ViewHolder holder, String path, int position) 
            this.holder = holder;
            this.path = path;
            this.position = position;
        

        public ViewHolder getHolder() 
            return holder;
        

        public String getPath() 
            return path;
        

        public int getPosition() 
            return position;
        

    

    class SetThumbnail extends AsyncTask<Thumbnail, Void, Bitmap> 

        ViewHolder holder;

        int position;

        @Override
        protected Bitmap doInBackground(Thumbnail... params) 
            // TODO Auto-generated method stub
            int pos = params[0].getPosition();
            position = pos;
            String path = params[0].getPath();
            holder = params[0].getHolder();

            Log.e("Ref", "Pos = " + pos + " " + holder);
            try 
                Bitmap thumbnail = BitmapFactory.decodeFile(path);
                thumbnail = Bitmap.createScaledBitmap(thumbnail, 100, 100,
                        false);

                return thumbnail;
             catch (Exception e) 

                return null;
            
        

        @Override
        protected void onPostExecute(Bitmap result) 
            // TODO Auto-generated method stub
            super.onPostExecute(result);

            if (holder != null && result != null) 

                Log.i("Ref", "Position = " + position + " " + holder);
                holder.img.setImageBitmap(result);
             else 
                holder.img.setImageResource(R.drawable.format_picture);
            
        
    

我也可以在启动 asynktask 之前通过注释行设置缩略图,但这会减慢我的列表膨胀。

【问题讨论】:

你的意思是当列表滚动时..然后图像会发生多次变化? 你说的是什么意思?“它会显示我的列表膨胀。” 对不起,这是我的错误 Amulya 它应该是“慢”而不是“显示” 是的 Amulya,当我滚动列表时,我的 imageview 多次更改了图像。例如 - 首先显示 img1,然后显示 img2 等。 imageview 中图像的变化取决于您滚动 listview 的速度 我已经发布了一个解决方案。让我知道它是否有效,如果您需要更多解释。 【参考方案1】:

首先在类级别声明 inflater 并且在 getview 中仅写入 if 条件如果 view 为 null 然后创建并运行它。一定会成功的。

   LayoutInflater inflter = (LayoutInflater) LayoutInflater
                .from(context);
         ......
         ......

 public View getView(int position, View convertView, ViewGroup parent) 
    // TODO Auto-generated method stub
    if (convertView == null) 

      view = inflter.inflate(R.layout.list_layout_home, null);
   

【讨论】:

【参考方案2】:

当您滚动时,ListView 会回收视图。您的问题正在发生,因为 AsyncTask 在视图被回收后完成,因此 "old" 图像显示在回收的视图中。解决方法如下:

第 1 步) 更新您的 get 视图以在开始 AsyncTask 之前包含一行

 holder.img.setTag(new Integer(position))
 new SetThumbnail().execute(new Thumbnail(holder, filePath, position));

第 2 步) 仅当位置与标签相同时才设置图像(更新您的onPostExecute):

@Override
protected void onPostExecute(Bitmap result) 
    if(holder == null) return;

    int viewPosition = (Integer) holder.img.getTag();
    if(position == viewPosition) 
        if(result != null) 
            holder.img.setImageBitmap(result);
        
        else 
            holder.img.setImageResource(R.drawable.format_picture);
        
    

【讨论】:

【参考方案3】:

正如我所怀疑的,您正在从 Internet 下载图像以设置在您的图像视图中。由于延迟加载,图像会发生变化或随机播放,这意味着您的 imageViews 在下载图像之前创建,并且当您滚动时,android 在它找到的第一个 imageview 中设置下载的图像。它找到的图像视图可能是错误的,因为在适配器中的 getview 方法中重用分配给对象的内存,这种重用性会导致图像随机播放。

但是,this is a nice project to solve this problem,我也使用并解决了我的问题。

【讨论】:

以上是关于滚动列表时视图意外更改的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI List 在任何视图更改时重置滚动

在方向更改时恢复列表视图中的项目和滚动位置

添加新列表时,回收站视图开始自动滚动

更改视图控制器时保持滚动位置

滚动列表视图时文本视图中的数据切换

Imageview 在滚动列表视图上自动更改