listview-recyclerview


```
   @Override
    public View getView(int position, View convertView, ViewGroup parent) {


        View view = null;
        ViewHolder viewHolder = null;
        //先创建一个内部类,用来放定义控件,然后在if语句中判断converview是否为空,第一次应该是空的,然后绑定id
        if (convertView == null) {
            //实例化view
            view = LayoutInflater.from(context).inflate(R.layout.richang_item, null);
            viewHolder = new ViewHolder();
            viewHolder.tv = view.findViewById(R.id.richang_item_list_tv);
            //将viewHolder打包
            view.setTag(viewHolder);
        } else {
            //第二次直接判断时,converview不为空,直接执行这一步
            view = convertView;
            viewHolder = (ViewHolder) view.getTag();
        }
        //赋值
        viewHolder.tv.setText(dailyList.get(position).getClassifyName());
        return view;
    }
```

https://blog.csdn.net/u012954720/article/details/80664943
https://blog.csdn.net/u012954720/article/details/80686747

#### ListView的核心在于layoutChildren函数
makeAndAddView----obtainView----adapter.getView,拿到view之后再使用setupChild加入到ListView里面去并放好位置(包含child自己的measure)

#### RecycleBin
RecycleBin中 mActiveViews:当前在屏幕上展示的view

mScrapViews :存储滑出屏幕的View; mViewTypeCount>1的时候,ScrapViews数组就会有多个值,分别缓存一个类型的item

mCurrentScrap :和mScrapViews 功能类似,mViewTypeCount=1,也就是listView中只有一种类型的item时(不包括header和footer),item是存入到mCurrentScrap中。

mViewTypeCount : 当前ListView 的item的种类

##### View的创建以及复用主要是在obtainView中实现

##### RecyclerBin回收和缓冲机制来展示LsitView

之前我们会在fillActiveViews方法中存储我们目前屏幕中展示的View; 之后又调用了调用了detachAllViewsFromParent()方法,这个方法会将所有ListView当中的子View全部清除掉,从而保证第二次Layout过程不会产生一份重复的数据。

RecycleBin的fillActiveViews()方法来缓存子View,待会儿将会直接使用这些缓存好的View来进行加载,而并不会重新执行一遍inflate过程,因此效率方面并不会有什么明显的影响

#### 滑动过程
incrementalDeltaY 表示触发事件在Y轴上的偏移量,我们会根据他的正负表示向上还是向下滑动,deltaY表示从手指按下到当前手指位置的距离

对于即将要滑出屏幕的数据,使用RecycleBin的addScrapView方法缓存,并且调用detachViewsFromParent将屏幕外的view detach掉,

对于屏幕上的view根据fillGap方法调用fillDown或者fillUp进而调用makeAndAddView,再调用obtinView获取view,最后使用setupChild 将 view 通过attachViewToParent或者addViewInLayout 方法 添加到屏幕上

#### setAdapter
ListView的setAdapter方法,首先会清楚之前adapter的相关设置,之后重新设置数据观察者,之后再调用requestLayout() 

#### notifyDataSetChanged 
requestLayout方法进行重绘


### ListView优化
#### 复用contentView
切忌每次 getView()新建,getView方法不能太复杂。ListView的核心原理就是重用View,如果重用view 不改变宽高,重用View可以减少重新分配缓存造成的内存频繁分配/回收

#### ViewHolder优化使用

ViewHolder的原因是findViewById方法耗时较大,如果控件个数过多,会严重影响性能,而使用ViewHolder主要是为了可以省去这个时间。通过setTag,getTag直接获取View。

#### 减少Item View的布局层级
这是所有Layout都必须遵循的,布局层级过深会直接导致View的测量与绘制浪费大量的时间。

#### 图片加载采用三级缓存,避免每次都要重新加载。

#### 尝试开启硬件加速来使ListView的滑动更加流畅。

### RecyclerView

mAttachedScrap: 用于缓存显示在屏幕上的 item 的 ViewHolder

mCachedViews:这个就重要得多了,滑动过程中的回收和复用都是先处理的这个 List,这个集合里存的 ViewHolder 的原本数据信息都在,所以可以直接添加到 RecyclerView 中显示,不需要再次重新 onBindViewHolder()

RecyclerViewPool

#### 回收复用过程

 mCachedViews默认大小为2,RecyclerViewPool 为5

mCachedViews 优先级高于 RecyclerViewPool,回收时,最新的 ViewHolder 都是往 mCachedViews 里放,如果它满了,那就移出一个扔到 ViewPool 里好空出位置来缓存最新的 ViewHolder。

复用时,也是先到 mCachedViews 里找 ViewHolder,但需要各种匹配条件,概括一下就是只有原来位置的卡位可以复用存在 mCachedViews 里的 ViewHolder,如果 mCachedViews 里没有,那么才去 ViewPool 里找。

在 ViewPool 里的 ViewHolder 都是跟全新的 ViewHolder 一样,只要 type 一样,有找到,就可以拿出来复用,重新绑定下数据即可

先复用再回收

### 优化方案和使用技巧

#### recyclerView.setHasFixedSize(true)

当Item的高度如是固定的,设置这个属性为true可以提高性能,尤其是当RecyclerView有条目插入、删除时性能提升更明显

RecyclerView在条目数量改变,会重新测量、布局各个item,如果设置了setHasFixedSize(true),由于item的宽高都是固定的,adapter的内容改变时,RecyclerView不会整个布局都重绘

#### 使用getExtraLayoutSpace为LayoutManager设置更多的预留空间
在RecyclerView的元素比较高,一屏只能显示一个元素的时候,第一次滑动到第二个元素会卡顿

RecyclerView (以及其他基于adapter的view,比如ListView、GridView等)使用了缓存机制重用子 view(即系统只将屏幕可见范围之内的元素保存在内存中,在滚动的时候不断的重用这些内存中已经存在的view,而不是新建view)

这个机制会导致一个问题,启动应用之后,在屏幕可见范围内,如果只有一张卡片可见,当滚动的时 候,RecyclerView找不到可以重用的view了,它将创建一个新的,因此在滑动到第二个feed的时候就会有一定的延时,但是第二个feed之 后的滚动是流畅的,因为这个时候RecyclerView已经有能重用的view了。

如何解决这个问题呢,其实只需重写getExtraLayoutSpace()方法
```
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this) {
    @Override
    protected int getExtraLayoutSpace(RecyclerView.State state) {
        return 300;
    }
};
```

#### RecyclerView 数据预取

#### 避免创建过多对象

#### 局部刷新
notifyItemChanged(int position)

如果必须用 notifyDataSetChanged(),那么最好设置 mAdapter.setHasStableIds(true)

#### 重写onScroll事件
对于大量图片的RecyclerView,滑动暂停后再加载

### RecyclerView与ListView对比
二级缓存
四级缓存


### RecyclerView与ListView缓存机制的不同

### 想改变listview的高度,怎么做?

```
     ViewGroup.LayoutParams params = listView.getLayoutParams();

      params.height = totalHeight; 
      
      listView.setLayoutParams(params);
```

### listview跟recyclerview上拉加载的时候分别应该如何处理?

### 如何自己实现RecyclerView的侧滑删除?

### RecyclerView的ItemTouchHelper的实现原理

### RecyclerView 滑动控制笔记
https://www.jianshu.com/p/e8117855c6a0
https://www.jianshu.com/p/055fa3cb964e
https://www.jianshu.com/p/d8379a77a782
]
recyclerview性能优化
https://www.jianshu.com/p/eabb00c500ef
尽量将复杂的数据处理操作放到异步中完成
优化RecyclerView的布局,避免将其与ConstraintLayout使用
如果ItemView的高度固定,可以使用setHasFixSize(true)
当UI是Tab feed流时,可以考虑使用RecycledViewPool来实现多个RecyclerView的缓存共享。

viewholder类的使用,减少查找控件的次数(findviewbyid()次数),将holder与view绑定来实现(.setTag()、.getTag())


实现控件之间的联动

Behavior

ListView采用的是RecyclerBin的回收机制在一些轻量级的List显示时效率更高

listview和recyclerview区别

1、recyclerview功能更强大,支持竖直、水平,gridview、瀑布流,局部刷新、局部删除,动画

2、listview要自定义viewholder,recyclerview 已经定义好了viewholder

3、缓存

猜你喜欢

转载自blog.csdn.net/weixin_42547039/article/details/109234628