Android RecyclerView与ListView局部刷新-飞
发布时间: 2023-07-06
Android ListView与RecyclerView局部刷新一、ListView

之前写过一篇关于ListView局部刷新的博客,这部分对其进行完善
,之前的链接为:Android模拟ListView点击下载和局部刷新

平时在写ListView的时候需要更改某些数据,这种情况我们一般会调用
notifyDataSetChanged()方法进行刷新,调用notifydatasetchange其实会导致adpter的getView方法被多次调用(画面上能显示多少就会被调用多少次),并且在有获取网络图片的情况下会可能造成大量闪动或卡顿,极大的影响用户体验(图片重新加载并闪动在ImageLoader框架中会出现,在glide框架中没有出现)。

所以我们需要做单行刷新来进行优化

这个是Google官方给出的解决方案:

private void updateSingleRow(ListView listView, long id) {          if (listView != null) {              int start = listView.getFirstVisiblePosition();              for (int i = start, j = listView.getLastVisiblePosition(); i <= j; i++)                  if (id == ((Messages) listView.getItemAtPosition(i)).getId()) {                      View view = listView.getChildAt(i - start);                      getView(i, view, listView);                      break;                  }          }      }

对于这个方法可以参考这个博客:android ListView 单条刷新方法实践及原理解析

可以看出来谷歌的方案是通过listview的getView方法将单行的所有内容都刷新一遍,但是这样如果是有加载网络图片的话可能也会造成闪动重新加载,所以我们需要单独刷新某个item中的某个控件来实现局部刷新

所以我们在Adapter中添加一个局部刷新的方法

/**     * 局部刷新     *     * @param mListView     * @param posi     */    public void updateSingleRow(ListView mListView, int posi) {        if (mListView != null) {            //获取第一个显示的item            int visiblePos = mListView.getFirstVisiblePosition();            //计算出当前选中的position和第一个的差,也就是当前在屏幕中的item位置            int offset = posi - visiblePos;            int lenth = mListView.getChildCount();            // 只有在可见区域才更新,因为不在可见区域得不到Tag,会出现空指针,所以这是必须有的一个步骤            if ((offset < 0) || (offset >= lenth)) return;            View convertView = mListView.getChildAt(offset);            ViewHolder viewHolder = (Vie(oc是什么意思?oc是指原创角色,original character的缩写。oc还有更多方面的意思。)wHolder) convertView.getTag();            //以下是处理需要处理的控件方法。。。。。        }    }

举个例子,简单的模拟在列表中点击下载并更新列表的demo
1.首先定义一个Bean对象
这里有一个图片url供Glide加载

public class Game {    private String gameName;    private long gameTotalSize;    private long gameDownSize;    private String gameUrl;    private int state;    public Game(String gameName, long gameTotalSize) {        this.gameName = gameName;        this.gameTotalSize = gameTotalSize;        gameUrl = "http://dynamic-image.yesky.com/600x-/uploadImages/upload/20140912/upload/201409/smkxwzdt1n1jpg.jpg";        this.gameDownSize = 0;    }    public String getGameUrl() {        return gameUrl;    }    public String getGameName() {        return gameName;    }    public long getGameTotalSize() {        return gameTotalSize;    }    public long getGameDownSize() {        return gameDownSize;    }    public void setGameDownSize(long gameDownSize) {        this.gameDownSize = gameDownSize;    }    public int getState() {        return state;    }    public void setState(int state) {        this.state = state;    }}

2.实现一个下载的模拟器(单例类)

public class DownLoadManager {    public interface DownCallBack{        void update(int posi,DownFile downFile);    }    private DownCallBack downCallBack;    public void setDownCallBack(DownCallBack downCallBack) {        this.downCallBack = downCallBack;    }    /**     * 下载文件类,不过在正常的项目中应该有一个ID或者url,     * 用来判断文件,在这个demo中就用列表的position来判断了     */    public static class DownFile {        public long total;        public long downSize;        public int downState;        public DownFile(long total, long downSize, int downState) {            this.total = total;            this.downSize = downSize;            this.downState = downState;        }    }    public static final int DOWN_WATE = 0X02;    public static final int DOWN_PAUST = 0X03;    public static final int DOWN_FINISH = 0X04;    public static final int DOWN_DOWNLOADING = 0X05;    private ExecutorService executorService;    private SparseArray<DownFile> downFileSparseArray;    private SparseArray<DownTask> downTaskSparseArray;    private static volatile DownLoadManager singl

微信