RecycleView与ListView的区别(最全???)

写的过程中发现有人写的也很完整,可以去看看 RecyclerView 和 ListView 使用对比分析。 2021/02/24补充

 

1. RecycleView的简单使用

主要工作是继承RecycleView.Adapter,并重写

1.RecyclerView.ViewHolder

2.onCreateViewHolder()用于创建ViewHolder实例,并把加载的布局传入到构造函数去,再把ViewHolder实例返回。

3.onBindViewHolder()则是用于对子项的数据进行赋值,会在每个子项被滚动到屏幕内时执行。position得到当前项的Fruit实例。

 

LayoutManager用于指定RecyclerView的布局方式。LinearLayoutManager指的是线性布局

 

一般使用方式:

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 
LinearLayoutManager layoutManager = new LinearLayoutManager(this); 
recyclerView.setLayoutManager(layoutManager); 
FruitAdapter adapter = new FruitAdapter(fruitList); recyclerView.setAdapter(adapter);

通过调用setOrientation()把布局的排列方向改为水平排列。

layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

除了LinearLayoutManager,RecyclerView还提供了GridLayoutManager(网格布局)和StaggeredGridLayoutManager(瀑布流布局)

 

2. RecycleView和ListView的区别(10点,不认可的欢迎评论)

可以参考: https://www.cnblogs.com/chen-ying/p/12386712.html

>还是自己也整理下吧

(1)基础使用

ListView需要使用自定义的ViewHolder和ConvertView来完成复用优化工作.(setTag && getTag)

RecycleView中的RecycleView.ViewHolder已经封装了复用,不需要自己优化了。

需要重写的方法肯定是不同的,翻看源码即知。(getView Vs onCreateViewHolder && onBindViewHolder)

(2)布局效果

RecycleView 只负责管理视图的重复利用,然后将布局的管理全权交给了 LayoutManager.

LayoutManager 是一个抽象类,系统已经为我们提供了三个相关的实现: LinearLayoutManager(线性布局效果)、GridLayoutManager(网格布局效果)、 StaggeredGridLayoutManager(瀑布流布局效果)。 RecyclerView 默认就能支持 线性布局、 网格布局、瀑布流布局 三种 ,通过配置和切换 LayoutManager 就可以获得不同的布局效果。所以 如果想自定义出更多布局效果,可以继承重写自己的LayoutManager,通过LayoutManager还可以 设置滚动方向、获取Item的位置

(3)空数据视图处理

ListView现有提供了setEmptyView方法,详细使用可参考: android笔记之ListView的setEmptyView方法 ,核心内容是在ListView同级设置空数据需要展示的视图,交由ListView进行数据是否为null的判断,从而设置empty的visible。

RecycleView没有setEmptyView方法,需要自己实现。可以参考: RecyclerView添加EmptyView ,核心内容是在重写的RecycleView中重写AdapterDataObserver并注册它, 在数据变化时判断数据是否为null,从而设置RecycleView本身以及EmptyView的显示和隐藏。

(4)HeaderView 与 FooterView

ListView中可以通过addHeaderView() 与 addFooterView()来添加头部item与底部item,来当我们需要实现下拉刷新或者上拉加载的情况;而且这两个API不会影响Adapter的编写。

使用时需要注意一些东西: addHeaderView与addFooterView

RecycleView没有这两个API,但可以在Adapter中编写,根据ViewHolder的Type与View来实现自己的Header,Footter与普通的item,但是这样就会影响到Adapter,改动较大。(这是常见的作法)

可以参照: RecyclerView头部尾部添加方法,实现原理是追加Header&Footer两种View,并设置三种类型(TYPE_HEAD&TYPE_FOOTER&TYPE_NORMAL),复写getItemViewType和修改getItemCount&onCreateViewHolder&onBindViewHolder。

onCreateViewHolder(ViewGroup parent, int viewType)

该方法中的viewType就是通过getItemViewType设置的。 详细可参照链接写个demo尝试下。

(5)动画效果

ListView没有为item提供动画,需要自己实现,具体可以参照:listview添加item动画

整体设置动画:

listView.setLayoutAnimation(getAnimationController());  

RecycleView有为item提供默认动画: DefaultItemAnimator,在使用RecycleView时进行增删的时候,会很明显看到动画效果。 若是想深入研究或自定义动画,可以参照: 自定义DefaultItemAnimator

 

(6)局部刷新

ListView的刷新notifyDataSetChanged,它会重绘所有item,所以不能应用于局部刷新。问题来了,ListView如何局部刷新呢?

a. 官方推荐方式:

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

// 获取到指定位置的View,主动调用getView方法 
View view = listView.getChildAt(position- listView.getFirstVisiblePosition()); 
getView(position, view, listView);

b.大众的方式: (在Adapter中添加一个局部刷新的方法)

public void updateItem(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 = (ViewHolder) convertView.getTag();
        // 已知view||viewholder,就可以进行自己想要的数据刷新
        // Tips:别忘了数据的更新
    }
}

RecycleView提供了局部刷新的方法: notifyItemChanged,源码如下.

public final void notifyItemChanged(int position) {
    mObservable.notifyItemRangeChanged(position, 1);
}

 

(7)ItemTouchHelper(拖拽&侧滑的实现)

ItemTouchHelper 是帮助Recycleview实现拖拽和侧滑的工具类。

// 1. 继承并重写 ItemTouchHelper.Callback
public class ItemTouchHelperCallback extends ItemTouchHelper.Callback{
    // 重写getMovementFlags()方法来指定可以支持的拖放和滑动的方向使用
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        mRecyclerAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        mRecyclerAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }
}
// 2. 建立与RecycleView的链接
    ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelperCallback());
    mItemTouchHelper.attachToRecyclerView(mRecyclerView);
// 补充说明
// onItemMove中主要做notifyItemMoved(fromPosition, toPosition); 以及数据的删除

以上可以轻松实现Recycleview的侧滑和拖拽的动画效果。

但是ListView没有提供此类方法,实现ListView的侧滑和拖拽可以参考: ListView的拖动和侧滑实现 (WindowManager实现拖动, ViewDragHelper实现侧滑), 写的比较清晰,大家可以尝试下。

 

(8)点击事件

ListView中提供了setOnItemClickListener、 setOnItemLongClickListener、setOnItemSelectedListener等方法,但要考虑设置了header和footer后的数组越界问题。

Recycleview没有提供这些方法,因此需要通过viewHolder去给子项设置具体的监听。(很常见,就不贴什么代码了)

 

(9)嵌套滚动机制

Android 触摸事件分发机制:Touch 事件在进行分发的时候,由父 View 向它的子 View 传递,一旦某个子 View 开始接收进行处理,那么接下来所有事件都将由这个 View 来进行处理,它的 ViewGroup 将不会再接收到这些事件,直到下一次手指按下。而嵌套滚动机制(NestedScrolling)就是为了弥补这一机制的不足,为了让子 View 能和父 View 同时处理一个 Touch 事件。

CollapsingToolbarLayout 这种需要嵌套滚动的机制才能达到效果的控件,那么 首选RecyclerView (Recycleview实现了NestedScrollingChild接口),因为 ListView无效。同样的,ScrollView 也是不支持嵌套滚动机制,但是你可以使用 NestedScrollView 。

 

(10)复用机制

ListView缓存机制

RecycleBin机制,RecycleBin定义在AbsListView当中。其中使用View[] mActiveViews存储View,是屏幕当中正在使用的View,mActiveViews中存储的View只能被获取一次;ArrayList[] mScrapViews和ArrayList mCurrentScrap则是用于存储移动出屏幕后被废弃的View。当getView方法在适配器中被调用的时候,其中传入的convertView如果不为空,就是从废弃的View当中获得的。

RecyclerView缓存机制

Scrap和Cache分别是通过position去找ViewHolder可以直接复用;

在RecyclerView当中也并不是每次都重新创建ViewHolder对象,不是每次都重新绑定ViewHolder数据,而是通过Recycler来获得下一个ViewHolder。

RecyclerView使用Recycler管理缓存ViewHolder,对于不同状态的ViewHolder存储在了不同的集合中,RecyclerView有四级缓存,分别是ArrayList mAttachedScrap、ArrayList mCachedViews、ViewCacheExtension mViewCacheExtension 和 RecycledViewPool mRecyclerPool,缓存的对象是ViewHolder。

而从RecycledViewPool 中复用的ViewHolder需要重新绑定数据,并且复用的ViewHolder只能复用于ViewType相同的表项,因为RecycledViewPool 对ViewHolder是按照ViewType分类存储的,RecycledViewPool通过type来获取ViewHolder,获取的ViewHolder是个全新,需要重新绑定数据;ViewCacheExtension自定义缓存,目前来说应用场景比较少却需慎用;从mCachedViews中复用ViewHolder只能复用于指定位置的item;而从mAttachedScrap复用的ViewHolder不需要重新创建也不需要重新绑定数据。

如果四个层级的缓存都没有命中,才会重新创建ViewHolder对象并且绑定。

 

 

 

3. RecycleView和ListView的缓存原理详解

第二章节大致介绍了两者的缓存机制。

详细的源码分析可以参照: 明日补充,一时找不到之前看的链接了。看中了人家的流程图。(实在是没有太多精力细细的肝源码了)

 

4. RecycleView如何优化?

可以参考: https://juejin.cn/post/6844903661726859271#heading-4

 

 

想认真的理解并掌握所有的区别以及原理,怕不是那么容易的事情哟。

知道的越多,不知道的越多。

 

参考文章:

 

https://www.cnblogs.com/chen-ying/p/12386712.html

https://www.jianshu.com/p/3e9aa4bdaefd

https://juejin.cn/post/6844903661726859271#heading-4

 

 

你可能感兴趣的:(Android,Android面试题,android)