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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Listview性能优化

發布時間:2025/7/14 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Listview性能优化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 首先,雖然大家都知道,還是提一下,利用好 convertView 來重用 View,切忌每次 getView() 都新建。ListView 的核心原理就是重用 View。ListView 中有一個回收器,Item 滑出界面的時候 View 會回收到這里,需要顯示新的 Item 的時候,就盡量重用回收器里面的 View。
  • 利用好 View Type,例如你的 ListView 中有幾個類型的 Item,需要給每個類型創建不同的 View,這樣有利于 ListView 的回收,當然類型不能太多;
  • 盡量讓 ItemView 的 Layout 層次結構簡單,這是所有 Layout 都必須遵循的;
  • 善用自定義 View,自定義 View 可以有效的減小 Layout 的層級,而且對繪制過程可以很好的控制;
  • 盡量能保證 Adapter 的 hasStableIds() 返回 true,這樣在 notifyDataSetChanged() 的時候,如果 id 不變,ListView 將不會重新繪制這個 View,達到優化的目的;
  • 每個 Item 不能太高,特別是不要超過屏幕的高度,可以參考 Facebook 的優化方法,把特別復雜的 Item 分解成若干小的 Item,特別推薦看一下這個文章:code.facebook.com/posts
  • 為了保證 ListView 滑動的流暢性,getView() 中要做盡量少的事情,不要有耗時的操作。特別是滑動的時候不要加載圖片,停下來再加載,這個庫可以幫助你 Glide:github.com/bumptech/gli
  • 使用 RecycleView 代替。 ListView 每次更新數據都要 notifyDataSetChanged(),有些太暴力了。RecycleView 在性能和可定制性上都有很大的改善,推薦使用。
    ?
  • ? 比如你的Item中有三個按鈕,你要為三個按鈕分別定義點擊事件,如何定義?

    也許你會在getView中這樣做
  • 1 button1.setOnclickListener(new View.OnClickListener() { 2 @override 3 public void onClick(View v) { 4 //balabalabala... 5 } 6 }); 7 button2.setOnclickListener(new View.OnClickListener() { 8 @override 9 public void onClick(View v) { 10 //balabalabala... 11 } 12 }); 13 button3.setOnclickListener(new View.OnClickListener() { 14 @override 15 public void onClick(View v) { 16 //balabalabala... 17 } 18 });

    ?

  • 如果你每屏顯示7個Item,你一共創建了21個listener對象在內存中,如果View回收不暢,會更多,這樣,在滾動的時候頻繁GC 就會導致卡頓(這里描述有誤,請看7月25日更新)

    如果你在Adapter初始化的時候創建一個Listener public MyAdapter () {myListener = new View.OnClickListener() {@overridepublic void onClick(View v) {v.getTag()v.getId()//balabalabala... }}); }

    ?

    通過傳入的View v這個參數判斷是哪一個button被點擊,這樣,無論View如何創建,你只創建了1個Listener對象

    這只是一個小細節,優化的方式要綜合使用,才會事半功倍


    ------------------7月24日更-----------------

    v.getTag() 這個tag本不是用來存數據的,通俗點講它和view 的Id是同一個東西,只不過tag的類型是Object。實際上在tag中存儲數據是不符合規范的方式

    但其實View類有兩種tag,
    setTag(Object?tag) 方法將tag保存在一個成員變量中,findViewWithTag正是遍歷此tag

    setTag(int key,?Object?tag) 方法是最終是調用View類中的setKeyedTag(int key, Object tag)
    這是一個私有方法
    他是用 SparseArray 實現的,我們可以把需要的東西存到這里面(其實觀察源碼可以發現,系統很多時候都是這樣做的)

    這里要注意一點,參數key必須是唯一的,那么我們可以這樣做
    那么需要先在res/values/strings.xml中添加
  • <resources> <item type="id" name="tag_first"></item> <item type="id" name="tag_second"></item> </resources>

    ?

  • 使用的時候寫成
  • view.setTag(R.id.tag_first, obj1); view.setTag(R.id.tag_second, obj2);

    ?

  • -------------------------關于如何綁定數據的問題-----------------

    有人問,如果這樣寫,所有button只能通過id區分邏輯,無法傳入每個item的數據

    我們可以將數據通過view 的tag帶進來
    1 public View getView(.....) { 2 .... 3 v.setTag(key, getItem(position)); 4 .... 5 } 然后在listener中通過v.getTag()將數據取出
    -----------------------7月25日update-------------------
    這里我有一個失誤
    如果listener里面的邏輯與當前的item有關,那么其實并不只是創建了21個listener對象
    1 public void getView (View convertView ,final int position ....) { 2 if (convertView == null) { 3 View v = LayoutInflater.from(mContext).inflate(...); 4 v.setOnclickListener(new View.OnClickListener () { 5 @override 6 public void onClick(View v) { 7 getItem(position); 8 } 9 }); 10 } else { 11 12 } 13 } 你看下,如果綁定數據在convertView為空的情況下確實只創建了有限個listener,
    但是在這種情況下綁定上的數據只有View創建時的7個,之后不為空的情況下沒有更換listener導致重用的view數據是新的,listener里面的position依然是過去創建view時的7個之一,不會變化(注意參數上的final)
    若在else里面再重新setListener,view是有重用,listener被換成新的,并與新的position綁定,老的listener就會變成一個廢對象,等待gc回收,隨著list滾動,越來越多
    關鍵是我們的業務與position這個參數有關
    1.重用?convertView?
    用以避免重復創建 View,重復創建 View 代價較大,而且如果重用 view 不改變寬高,重用View可以減少重新分配緩存造成的內存頻繁分配/回收;

    2. 避免在 getView 中有 重復調用的 findViewById
    findViewById 的實現是遍歷,如果你定義的 View 越復雜代價越大。
    Google 推薦的做法是用 ViewHolder,然后保存在 view 的 tag 中。現在 RecyclerView 也是強制使用 ViewHolder 了。

    3. 設置 View (如 TextView#setText )之前先對比數據是否有改變
    一般來說,【比較兩個數據的代價】遠小于【 View 的重繪的代價】

    4.?避免在 getView 函數中直接加載 Image 或做其他比較耗時的操作
    加載本地 Image 需要載入內存以及解析 Bitmap ,都是比較耗時的操作。
    用戶快速滑動列表時,會大量調用 getView ,而 getView 是在主線程中被調用的。如果你在 getView 函數中直接加載 Image 或做其他耗時操作,就會造成滑動比較卡。加載 ImageView 的解決方案就是開一個線程去把做這事。有很多第三庫可以做這事。

    5. ListView 中元素避免半透明
    半透明繪制需要大量乘法計算,在滑動時不停重繪會造成大量的計算,在比較差的機子上會比較卡。在設計上能不半透明就不不半透明。實在要弄的話我個人是用個比較偷懶的方法,是在滑動的時候把半透明設置成不透明,滑動完再重新設置成半透明。

    6. 盡量開啟硬件加速
    硬件加速提升巨大,避免使用一些不支持的函數導致含淚關閉某個地方的硬件加速。
    當然這一條不只是對 ListView。

    7.用 ListView 威力加強版 -- RecyclerView
    更多的新武將,更多的姿勢,更規范的使用,更好用的動畫,更加強大的變化 ? 轉載自知乎(http://www.zhihu.com/question/19703384

    總結

    以上是生活随笔為你收集整理的Listview性能优化的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。