在搞懂這個問題之前,我們最好先搞明白ListView和RecyclerView的實現(xiàn)原理,這里推薦兩篇文章:
那么,ListView和RecyclerView的主要區(qū)別有哪些呢?
一、緩存機制的不同
這里可以參考《Android ListView 與 RecyclerView 對比淺析—緩存機制》
二、布局效果、常用功能與API等
參考《ListView 與 RecyclerView 簡單對比》
使用上
ListView:
- 繼承重寫B(tài)aseAdapter類;
- 自定義ViewHolder與convertView的優(yōu)化;
RecyclerView:
- 繼承重寫RecyclerView.Adapter與RecyclerView.ViewHolder
- 設(shè)置LayoutManager,以及l(fā)ayout的布局效果
區(qū)別:
- ViewHolder的編寫規(guī)范化,ListView是需要自己定義的,而RecyclerView是規(guī)范好的;
- RecyclerView復(fù)用item全部搞定,不需要像ListView那樣setTag()與getTag();
- RecyclerView多了一些LayoutManager工作,但實現(xiàn)了布局效果多樣化;
布局效果
- ListView 的布局比較單一,只有一個縱向效果;
- RecyclerView 的布局效果豐富, 可以在LayoutMananger中設(shè)置:線性布局(縱向,橫向),表格布局,瀑布流布局
- 在RecyclerView 中,如果存在的LayoutManager不能滿足需求,可以在LayoutManager的API中自定義Layout:
例如:scrollToPosition(), setOrientation(), getOrientation(), findViewByPosition()等等;
空數(shù)據(jù)處理
在ListView中有個setEmptyView() 用來處理Adapter中數(shù)據(jù)為空的情況;但是在RecyclerView中沒有這個API,所以在RecyclerView中需要進行一些數(shù)據(jù)判斷來實現(xiàn)數(shù)據(jù)為空的情況;
HeaderView 與 FooterView
- 在ListView中可以通過addHeaderView() 與 addFooterView()來添加頭部item與底部item,來當(dāng)我們需要實現(xiàn)下拉刷新或者上拉加載的情況;而且這兩個API不會影響Adapter的編寫;
- 但是RecyclerView中并沒有這兩個API,所以當(dāng)我們需要在RecyclerView添加頭部item或者底部item的時候,我們可以在Adapter中自己編寫,根據(jù)ViewHolder的Type與View來實現(xiàn)自己的Header,F(xiàn)ootter與普通的item,但是這樣就會影響到Adapter的數(shù)據(jù),比如position,添加了Header與Footter后,實際的position將大于數(shù)據(jù)的position;
局部刷新
- 在ListView中通常刷新數(shù)據(jù)是用notifyDataSetChanged() ,但是這種刷新數(shù)據(jù)是全局刷新的(每個item的數(shù)據(jù)都會重新加載一遍),這樣一來就會非常消耗資源;
- RecyclerView中可以實現(xiàn)局部刷新,例如:notifyItemChanged();
- 但是如果要在ListView實現(xiàn)局部刷新,依然是可以實現(xiàn)的,當(dāng)一個item數(shù)據(jù)刷新時,我們可以在Adapter中,實現(xiàn)一個onItemChanged()方法,在方法里面獲取到這個item的position(可以通過getFirstVisiblePosition()),然后調(diào)用getView()方法來刷新這個item的數(shù)據(jù);
動畫效果:
- 在RecyclerView中,已經(jīng)封裝好API來實現(xiàn)自己的動畫效果;有許多動畫API,例如:notifyItemChanged(), notifyDataInserted(), notifyItemMoved()等等;如果我們需要淑賢自己的動畫效果,我們可以通過相應(yīng)的接口實現(xiàn)自定義的動畫效果(RecyclerView.ItemAnimator類),然后調(diào)用RecyclerView.setItemAnimator() (默認(rèn)的有SimpleItemAnimator與DefaultItemAnimator);
- 但是ListView并沒有實現(xiàn)動畫效果,但我們可以在Adapter自己實現(xiàn)item的動畫效果;
ItemTouchHelper:
- 創(chuàng)建ItemTouchHelper實例,然后在ItemTouchHelper.SimpleCallback(),然后在Callback中實現(xiàn)getMovementFlags(), onMove(), onSwiped(), 最后調(diào)用RecyclerView的attachToRecyclerView方法;
Item點擊事件:
- 在ListView中有onItemClickListener(), onItemLongClickListener(), onItemSelectedListener(), 但是添加HeaderView與FooterView后就不一樣了,因為HeaderView與FooterView都會算進position中,這時會發(fā)現(xiàn)position會出現(xiàn)變化,可能會拋出數(shù)組越界,為了解決這個問題,我們在getItemId()方法(在該方法中HeaderView與FooterView返回的值是-1)中通過返回id來標(biāo)志對應(yīng)的item,而不是通過position來標(biāo)記;但是我們可以在Adapter中針對每個item寫在getView()中會比較合適;
- 而在RecyclerView中,提供了唯一一個API:addOnItemTouchListener(),監(jiān)聽item的觸摸事件;我們可以通過RecyclerView的addOnItemTouchListener()加上系統(tǒng)提供的Gesture Detector來實現(xiàn)像ListView那樣監(jiān)聽某個item某個操作方法;
嵌套滾動機制:
- 在事件分發(fā)機制中,Touch事件在進行分發(fā)的時候,由父View向子View傳遞,一旦子View消費這個事件的話,那么接下來的事件分發(fā)的時候,父View將不接受,由子View進行處理;但是與Android的事件分發(fā)機制不同,嵌套滾動機制(Nested Scrolling)可以彌補這個不足,能讓子View與父View同時處理這個Touch事件,主要實現(xiàn)在于NestedScrollingChild與NestedScrollingParent這兩個接口;而在RecyclerView中,實現(xiàn)的是NestedScrollingChild,所以能實現(xiàn)嵌套滾動機制;
- ListView就沒有實現(xiàn)嵌套滾動機制;