列表滑動(dòng)性能優(yōu)化是一個(gè)老生常談的問(wèn)題粥脚,最近在做項(xiàng)目的時(shí)候又遇到了列表滑動(dòng)卡頓的問(wèn)題捂人,我在經(jīng)過(guò)多次思考和嘗試后,終于找到了滑動(dòng)卡頓的元兇膏燃,于是將經(jīng)驗(yàn)總結(jié)下來(lái)。
ViewHolder
先說(shuō)說(shuō)最常規(guī)的ViewHolder何什。ViewHolder的出現(xiàn)是為了解決在綁定視圖數(shù)據(jù)的時(shí)候使用findViewById
遍歷視圖樹(shù)(以深度優(yōu)先的方式)查找視圖引起耗時(shí)操作的問(wèn)題组哩,將第一次查找到的視圖放入靜態(tài)的ViewHolder中,以后綁定新數(shù)據(jù)時(shí)直接從ViewHolder中拿到視圖引用处渣。在ListView中使用ViewHolder是基本的優(yōu)化思路伶贰,當(dāng)然最好的是直接使用RecyclerView,它自帶了ViewHolder罐栈。(推薦使用MultiType作為RecyclerView
的Adapter黍衙,這個(gè)庫(kù)設(shè)計(jì)的很優(yōu)美)
數(shù)據(jù)處理
很多時(shí)候從我們要對(duì)服務(wù)器上獲取下來(lái)的列表數(shù)據(jù)進(jìn)行一次二次加工,以便轉(zhuǎn)化為我們界面上要顯示的數(shù)據(jù)荠诬,這些操作可能會(huì)比較耗時(shí)琅翻。比如字符串拼接、時(shí)間格式化等操作都是比較耗時(shí)的操作柑贞。比較好的實(shí)踐是將列表數(shù)據(jù)的加工在notifyDataSetChanged()
之前在后臺(tái)線程做好方椎,在Adapter中只做數(shù)據(jù)的綁定。
Item View 的變化
有時(shí)候我們會(huì)根據(jù)數(shù)據(jù)類(lèi)型來(lái)控制一個(gè)View的顯隱凌外,當(dāng)給一個(gè)View設(shè)置setVisibility(View.GONE)
的時(shí)候辩尊,會(huì)觸發(fā)布局的重新測(cè)量、布局康辑、繪制等操作摄欲,若itemView的布局比較復(fù)雜,重新測(cè)量繪制會(huì)很耗時(shí)間疮薇,引起列表卡頓胸墙。這個(gè)時(shí)候可以將數(shù)據(jù)和itemView分解成不同的類(lèi)型,根據(jù)類(lèi)型來(lái)綁定對(duì)應(yīng)的itemView按咒,減少布局的重繪操作迟隅。
重用OnClickListener
通常我們?yōu)锽utton設(shè)置點(diǎn)擊事件的時(shí)候都是直接創(chuàng)建一個(gè)匿名內(nèi)部類(lèi)的對(duì)象(new OnClickListener{}
),習(xí)慣了這種綁定事件的方式后我們可能在列表中也這么做。在列表滑動(dòng)的時(shí)候會(huì)不停的重復(fù)創(chuàng)建新的OnClickListener
的操作智袭,舊的OnClickListener
會(huì)被標(biāo)記為需要垃圾回收奔缠,當(dāng)需要回收的對(duì)象過(guò)多的時(shí)候會(huì)引起GC,導(dǎo)致列表卡頓吼野⌒0ィ可以創(chuàng)建一個(gè)通用的OnClickListener
,把數(shù)據(jù)放入Button的Tag中瞳步,根據(jù)id來(lái)判斷是哪個(gè)Button執(zhí)行了點(diǎn)擊闷哆,來(lái)取出數(shù)據(jù)、執(zhí)行不同的邏輯单起。
圖片的異步加載
用Glide抱怔、Picasso、Fresco等圖片異步加載框架嘀倒。
界面優(yōu)化
優(yōu)化布局層級(jí)減少過(guò)渡繪制屈留、優(yōu)化布局方式提高布局效率。關(guān)于這點(diǎn)官方推薦使用ConstraintLayout
括儒,在我目前的實(shí)踐中绕沈,ConstraintLayout
作為RecyclerView
的Item布局的時(shí)候可能會(huì)有卡頓現(xiàn)象(主要是布局重繪引起的)。