日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ListView与GridView优化

發(fā)布時間:2025/3/8 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ListView与GridView优化 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

  ListView是Android中最常用的控件,通過適配器來進行數(shù)據(jù)適配然后顯示出來,而其性能是個很值得研究的話題。本文與你一起探討Google I/O提供的優(yōu)化Adapter方案,歡迎大家交流。

?

聲明

  歡迎轉(zhuǎn)載,但請保留文章原始出處:)?

    博客園:http://www.cnblogs.com

    農(nóng)民伯伯:?http://over140.cnblogs.com

?

正文

  一、準備

    1.1  了解關于Google IO大會關于Adapter的優(yōu)化,參考以下文章:

      Android開發(fā)之ListView 適配器(Adapter)優(yōu)化

      Android開發(fā)——09Google I/O之讓Android UI性能更高效(1)

      PDF下載:Google IO.pdf

    1.2  準備測試代碼:

      Activity

????private?TestAdapter?mAdapter;

????
private?String[]?mArrData;
????
private?TextView?mTV;

????@Override
????
protected?void?onCreate(Bundle?savedInstanceState)?{
????????
super.onCreate(savedInstanceState);
????????setContentView(R.layout.main);
????????mTV?
=?(TextView)?findViewById(R.id.tvShow);

????????mArrData?
=?new?String[1000];
????????
for?(int?i?=?0;?i?<?1000;?i++)?{
????????????mArrData[i]?
=?"Google?IO?Adapter" + i;
????????}
????????mAdapter?
=?new?TestAdapter(this,?mArrData);
????????((ListView)?findViewById(android.R.id.list)).setAdapter(mAdapter);
????}

      代碼說明:模擬一千條數(shù)據(jù),TestAdapter繼承自BaseAdapter,main.xml見文章末尾下載。

?

  二、測試

    測試方法:手動滑動ListView至position至50然后往回滑動,充分利用convertView不等于null的代碼段。

    2.1  方案一

      按照Google I/O介紹的第二種方案,把item子元素分別改為4個和10個,這樣效果更佳明顯。

      2.1.1  測試代碼

????????private?int?count?=?0;
????????
private?long?sum?=?0L;
????????@Override
????????
public?View?getView(int?position,?View?convertView,?ViewGroup?parent)?{
????????????
//開始計時
????????????long?startTime?=?System.nanoTime();
????????????
????????????
if?(convertView?==?null)?{
????????????????convertView?
=?mInflater.inflate(R.layout.list_item_icon_text,
????????????????????????
null);
????????????}
????????????((ImageView)?convertView.findViewById(R.id.icon1)).setImageResource(R.drawable.icon);
????????????((TextView)?convertView.findViewById(R.id.text1)).setText(mData[position]);
????????????((ImageView)?convertView.findViewById(R.id.icon2)).setImageResource(R.drawable.icon);
????????????((TextView)?convertView.findViewById(R.id.text2)).setText(mData[position]);
????????????
????????????
//停止計時
????????????long?endTime?=?System.nanoTime();
????????????
//計算耗時
????????????long?val?=?(endTime?-?startTime)?/?1000L;
????????????Log.e(
"Test",?"Position:"?+?position?+?":"?+?val);
????????????
if?(count?<?100)?{
????????????????
if?(val?<?1000L)?{
????????????????????sum?
+=?val;
????????????????????count
++;
????????????????}
????????????}?
else
????????????????mTV.setText(String.valueOf(sum?
/?100L));//顯示統(tǒng)計結(jié)果
????????????return?convertView;
????????}

?      2.1.2  測試結(jié)果(微秒除以1000,見代碼)

次數(shù)

4個子元素

10個子元素

第一次

?366

723

第二次

356?

689

第三次

?371

692

第四次

356?

696

第五次

?371

662

? 2.2  方案二

      按照Google I/O介紹的第三種方案,是把item子元素分別改為4個和10個。

      2.2.1  測試代碼

????????private?int?count?=?0;
????????
private?long?sum?=?0L;

????????@Override
????????
public?View?getView(int?position,?View?convertView,?ViewGroup?parent)?{
????????????
//?開始計時
????????????long?startTime?=?System.nanoTime();

????????????ViewHolder?holder;
????????????
if?(convertView?==?null)?{
????????????????convertView?
=?mInflater.inflate(R.layout.list_item_icon_text,
????????????????????????
null);
????????????????holder?
=?new?ViewHolder();
????????????????holder.icon1?
=?(ImageView)?convertView.findViewById(R.id.icon1);
????????????????holder.text1?
=?(TextView)?convertView.findViewById(R.id.text1);
????????????????holder.icon2?
=?(ImageView)?convertView.findViewById(R.id.icon2);
????????????????holder.text2?
=?(TextView)?convertView.findViewById(R.id.text2);
????????????????convertView.setTag(holder);
????????????}
????????????
else{
????????????????holder?
=?(ViewHolder)convertView.getTag();
????????????}
????????????holder.icon1.setImageResource(R.drawable.icon);
????????????holder.text1.setText(mData[position]);
????????????holder.icon2?.setImageResource(R.drawable.icon);
????????????holder.text2.setText(mData[position]);

????????????
//?停止計時
????????????long?endTime?=?System.nanoTime();
????????????
//?計算耗時
????????????long?val?=?(endTime?-?startTime)?/?1000L;
????????????Log.e(
"Test",?"Position:"?+?position?+?":"?+?val);
????????????
if?(count?<?100)?{
????????????????
if?(val?<?1000L)?{
????????????????????sum?
+=?val;
????????????????????count
++;
????????????????}
????????????}?
else
????????????????mTV.setText(String.valueOf(sum?
/?100L));//?顯示統(tǒng)計結(jié)果
????????????return?convertView;
????????}
????}

????
static?class?ViewHolder?{
????????TextView?text1;
????????ImageView?icon1;
????????TextView?text2;
????????ImageView?icon2;
????}

?      2.2.2  測試結(jié)果(微秒除以1000,見代碼)

次數(shù)

4個子元素

10個子元素

第一次

?311

?417

第二次

?291

?441

第三次

?302

?462

第四次

?286

?444

第五次

?299

?436

?

2.3  方案三

      此方案為“Henry Hu”提示,API Level 4以上提供,這里順帶測試了一下不使用靜態(tài)內(nèi)部類情況下性能。

2.3.1  測試代碼 ????????@Override
????????
public?View?getView(int?position,?View?convertView,?ViewGroup?parent)?{
????????????
//?開始計時
????????????long?startTime?=?System.nanoTime();

????????????
if?(convertView?==?null)?{
????????????????convertView?
=?mInflater.inflate(R.layout.list_item_icon_text,?null);
????????????????convertView.setTag(R.id.icon1,?convertView.findViewById(R.id.icon1));
????????????????convertView.setTag(R.id.text1,?convertView.findViewById(R.id.text1));
????????????????convertView.setTag(R.id.icon2,?convertView.findViewById(R.id.icon2));
????????????????convertView.setTag(R.id.text2,?convertView.findViewById(R.id.text2));
????????????}
????????????((ImageView)?convertView.getTag(R.id.icon1)).setImageResource(R.drawable.icon);
????????????((ImageView)?convertView.getTag(R.id.icon2)).setImageResource(R.drawable.icon);
????????????((TextView)?convertView.getTag(R.id.text1)).setText(mData[position]);
????????????((TextView)?convertView.getTag(R.id.text2)).setText(mData[position]);

????????????
//?停止計時
????????????long?endTime?=?System.nanoTime();
????????????
//?計算耗時
????????????long?val?=?(endTime?-?startTime)?/?1000L;
????????????Log.e(
"Test",?"Position:"?+?position?+?":"?+?val);
????????????
if?(count?<?100)?{
????????????????
if?(val?<?1000L)?{
????????????????????sum?
+=?val;
????????????????????count
++;
????????????????}
????????????}?
else
????????????????mTV.setText(String.valueOf(sum?
/?100L)?+?":"?+?nullcount);//?顯示統(tǒng)計結(jié)果
????????????return?convertView;
????????}

?       2.3.2  測試結(jié)果(微秒除以1000,見代碼)

        第一次:450

        第二次:467

        第三次:472

        第四次:451

第五次:441

?

四、總結(jié)

    4.1  首先有一個認識是錯誤的,我們先來看截圖:

      ?

      

      可以發(fā)現(xiàn),只有第一屏(可視范圍)調(diào)用getView所消耗的時間遠遠多于后面的,通過對

convertView == null內(nèi)代碼監(jiān)控也是同樣的結(jié)果。也就是說ListView僅僅緩存了可視范圍內(nèi)的View,隨后的滾動都是對這些View進行數(shù)據(jù)更新。不管你有多少數(shù)據(jù),他都只用ArrayList緩存可視范圍內(nèi)的View,這樣保證了性能,也造成了我以為ListView只緩存View結(jié)構不緩存數(shù)據(jù)的假相(不會只有我一人這么認為吧- - #)。這也能解釋為什么GOOGLE優(yōu)化方案一比二高很多的原因。那么剩下的也就只有findViewById比較耗時了。據(jù)此大家可以看看AbsListView的源代碼,看看 obtainView這個方法內(nèi)的代碼及RecycleBin這個類的實現(xiàn),歡迎分享。

      此外了解這個原理了,那么以下代碼不運行你可能猜到結(jié)果了:

????????????if?(convertView?==?null)?{
????????????????convertView?
=?mInflater.inflate(R.layout.list_item_icon_text,?null);
????????????????((ImageView)?convertView.findViewById(R.id.icon1)).setImageResource(R.drawable.icon);
????????????????((TextView)?convertView.findViewById(R.id.text1)).setText(mData[position]);
????????????????((ImageView)?convertView.findViewById(R.id.icon2)).setImageResource(R.drawable.icon);
????????????????((TextView)?convertView.findViewById(R.id.text2)).setText(mData[position]);
????????????}
????????????
else
????????????????
return?convertView;

      沒錯,你會發(fā)現(xiàn)滾動時會重復顯示第一屏的數(shù)據(jù)!

      子控件里的事件因為是同一個控件,也可以直接放到convertView == null 代碼塊內(nèi)部,如果需要交互數(shù)據(jù)比如position,可以通過tag方式來設置并獲取當前數(shù)據(jù)。

    4.2  本文方案一與方案二對比

      這里推薦如果只是一般的應用(一般指子控件不多),無需都是用靜態(tài)內(nèi)部類來優(yōu)化,使用第二種方案即可;反之,對性能要求較高時可采用。此外需要提醒的是這里也是用空間換時間的做法,View本身因為setTag而會占用更多的內(nèi)存,還會增加代碼量;而findViewById會臨時消耗更多的內(nèi)存,所以不可盲目使用,依實際情況而定。

    4.3  方案三

      此方案為“Henry Hu”提示,API Level 4以上支持,原理和方案三一致,減少findViewById次數(shù),但是從測試結(jié)果來看效果并不理想,這里不再做進一步的測試。

?

  五、推薦文章

    Android,誰動了我的內(nèi)存(1)

    Android 內(nèi)存泄漏調(diào)試

?

六、后期維護

?????????? 2011-3-30? 參見這里(http://www.javaeye.com/topic/971782)的討論,據(jù)此將計劃寫續(xù)篇。

?

結(jié)束

  對于Google I/O大會這個優(yōu)化方案一直抱遲疑態(tài)度,此番測試總算是有了更進一步的了解,歡迎大家先測試后交流,看看還有什么辦法能夠再優(yōu)化一點。?

轉(zhuǎn)載于:https://www.cnblogs.com/lanzhi/p/6469678.html

總結(jié)

以上是生活随笔為你收集整理的ListView与GridView优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。