1. 程式人生 > >Andorid中幾種簡單又常見的ListView的優化方案!

Andorid中幾種簡單又常見的ListView的優化方案!

Android中的ListView應該算是佈局中幾種最常用的元件之一了,使用也十分方便,下面將介紹ListView幾種比較常見的優化方法:

首先我們給出一個沒有任何優化的Listview的Adapter類,我們這裡都繼承自BaseAdapter,這裡我們使用一個包含100個字串的List集合來作為ListView的專案所要顯示的內容,每一個條目都是一個自定義的元件,這個元件中只包含一個textview:

Activity:

package com.alexchen.listviewoptimize;

import java.util.ArrayList;
import java.util.List
; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView;
//create by AndCnFeng 2016.11.13
public class
MainActivity extends Activity
{ private ListView lv_demo; private List<String> list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv_demo = (ListView) findViewById(R.id.lv_demo); //list為要載入的條目文字的集合,這裡總共是100條
list = new ArrayList<String>(); for (int i = 0; i < 100; i++) { list.add("條目" + i); } lv_demo.setAdapter(new MyAdapter()); } private class MyAdapter extends BaseAdapter { @Override public int getCount() { return list.size(); } @Override public View getView(int position, View convertView, ViewGroup parent) { //listview_item裡只有一個textview View view = View.inflate(MainActivity.this, R.layout.listview_item, null); //使用每一次都findviewById的方法來獲得listview_item內部的元件 TextView tv_item = (TextView) view.findViewById(R.id.tv_item); tv_item.setText(list.get(position)); return view; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } } }

優化一:

也是最普通的優化,就在MyAdapter類中的getView方法中,我們注意到,上面的寫法每次需要一個View物件時,都是去重新inflate一個View出來返回去,沒有實現View物件的複用,而實際上對於ListView而言,只需要保留能夠顯示的最大個數的view即可,其他新的view可以通過複用的方式使用消失的條目的view,而getView方法裡也提供了一個引數:convertView,這個就代表著可以複用的view物件,當然這個物件也可能為空,當它為空的時候,表示該條目view第一次建立,所以我們需要inflate一個view出來,所以在這裡,我們使用下面這種方式來重寫getView方法:

@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View view;
			// 判斷convertView的狀態,來達到複用效果
			if (null == convertView) {
				//如果convertView為空,則表示第一次顯示該條目,需要建立一個view
				view = View.inflate(MainActivity.this, R.layout.listview_item,
						null);
			} else {
				//否則表示可以複用convertView
				view = convertView;
			}
			// listview_item裡只有一個textview
			TextView tv_item = (TextView) view.findViewById(R.id.tv_item);
			tv_item.setText(list.get(position));
			return view;
		}

優化二:

上面是對view物件的複用做的優化,我們經過上面的優化之後,我們不需要每一個view都重新生成了。下面我們來解決下一個每一次都需要做的工作,那就是view中元件的查詢:

TextView tv_item = (TextView) view.findViewById(R.id.tv_item);

實際上,findViewById是到xml檔案中去查詢對應的id,可以想象如果元件多的話也是挺費事的,如果我們可以讓view內的元件也隨著view的複用而複用,那該是多美好的一件事啊。。實際上谷歌也推薦了一種優化方法來做應對,那就是重新建一個內部靜態類,裡面的成員變數跟view中所包含的元件個數型別相同,我們這裡的view只包含了一個TextView,所以我們的這個靜態類如下:

private static class ViewHolder {
		private TextView tvHolder;
	}

那麼這個viewHolder類我們要如何使用才可以達到複用效果呢?基本思路就是在convertView為null的時候,我們不僅重新inflate出來一個view,並且還需要進行findviewbyId的查詢工作,但是同時我們還需要獲取一個ViewHolder類的物件,並將findviewById的結果賦值給ViewHolder中對應的成員變數。最後將holder物件與該view物件“綁”在一塊。

當convertView不為null時,我們讓view=converView,同時取出這個view對應的holder物件,就獲得了這個view物件中的TextView元件,它就是holder中的成員變數,這樣在複用的時候,我們就不需要再去findViewById了,只需要在最開始的時候進行數次查詢工作就可以了。這裡的關鍵在於如何將view與holder物件進行繫結,那麼就需要用到兩個方法:setTag和getTag方法了:

@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View view;
			ViewHolder holder;
			// 判斷convertView的狀態,來達到複用效果
			if (null == convertView) {
				// 如果convertView為空,則表示第一次顯示該條目,需要建立一個view
				view = View.inflate(MainActivity.this, R.layout.listview_item,
						null);
				//新建一個viewholder物件
				holder = new ViewHolder();
				//將findviewbyID的結果賦值給holder對應的成員變數
				holder.tvHolder = (TextView) view.findViewById(R.id.tv_item);
				// 將holder與view進行繫結
				view.setTag(holder);
			} else {
				// 否則表示可以複用convertView
				view = convertView;
				holder = (ViewHolder) view.getTag();
			}
			// 直接操作holder中的成員變數即可,不需要每次都findViewById
			holder.tvHolder.setText(list.get(position));
			return view;
		}

經過上面的做法,可能大家感覺不太到優化的效果,根據Google的文件,實際優化效果在百分之5左右。

優化三:

上面的兩個例子中ListView都是顯示的本地的List集合中的內容,List的長度也只有100個,我們可以毫不費力一次性載入完這100個數據;但是實際應用中,我們往往會需要使用Listview來顯示網路上的內容,比如說我們拿使用ListView顯示新聞為例:

其一:假如網路情況很好,我們使用的手機也許能夠一下子載入完所有新聞資料,然後顯示在ListView中,使用者可能感覺還好,假如說在網路不太順暢的情況下,使用者載入完所有網路的資料,可能這個list是1000條新聞,那麼使用者可能需要面對一個空白的Activity好幾分鐘,這個顯然是不合適的

其二:我們知道Android虛擬機器給每個應用分配的執行時記憶體是一定的,一般效能不太好的機器只有16M,好一點的可能也就是64M的樣子,假如說我們現在要瀏覽的新聞總數為一萬條,即便是網路很好的情況下,我們可以很快的載入完畢,但是多數情況下也會出現記憶體溢位從而導致應用崩潰的情況。

那麼為了解決上面的兩個問題,我們需要進行分批載入,比如說1000條新聞的List集合,我們一次載入20條,等到使用者翻頁到底部的時候,我們再新增下面的20條到List中,再使用Adapter重新整理ListView,這樣使用者一次只需要等待20條資料的傳輸時間,不需要一次等待好幾分鐘把資料都載入完再在ListView上顯示。其次這樣也可以緩解很多條新聞一次載入進行產生OOM應用崩潰的情況。

實際上,分批載入也不能完全解決問題,因為雖然我們在分批中一次只增加20條資料到List集合中,然後再重新整理到ListView中去,假如有10萬條資料,如果我們順利讀到最後這個List集合中還是會累積海量條數的資料,還是可能會造成OOM的情況,這時候我們就需要用到分頁,比如說我們將這10萬條資料分為1000頁,每一頁100條資料,每一頁載入時都覆蓋掉上一頁中List集合中的內容,然後每一頁內再使用分批載入,這樣使用者的體驗就會相對好一些。

相關推薦

Andorid簡單常見ListView優化方案

Android中的ListView應該算是佈局中幾種最常用的元件之一了,使用也十分方便,下面將介紹ListView幾種比較常見的優化方法: 首先我們給出一個沒有任何優化的Listview的Adapter類,我們這裡都繼承自BaseAdapter,這裡我們使用一個包含10

昊天善圈講述區塊鏈技術應用開發過程常見的區塊鏈系統類型:

玩遊戲 通過 遊戲 返利 應用 自定義 理財 區塊鏈 區塊鏈寵物系統 1.區塊鏈挖礦系統:手手機挖礦遊戲,挖得多賺得多,玩法自定義2.區塊鏈積分商城:多種積分獲取方式,積分可用於商城交易3.區塊鏈貨幣系統:自行發行數字貨幣,多種獲取貨幣方式,數字貨幣交易商城,打造數字貨幣全

Thinkphp編程常見的實用技巧講解

要掌握 true 方法 ech admin 字段 status _id 同時 在Thinkphp編程中集成了很多用起來非常方便的方法。對於剛接觸的編程人員來說,可謂是只要掌握並靈活運用了,那麽就可以達到事半功倍的效果了,下面就來為大家詳細的講解一下。   1. getFie

Java常見的NPE問題

avi oar 返回 對象 [] 報錯 不能 alt public 1、Map下的NPE 直接上代碼: public class User { private Integer id; private String name;

Open stack生產環境常見的網絡結構

定義 roc min ffffff 網絡類型 提供服務 color neu 不可 一、概述 想必接觸過Open stack的人都知道,Opens stack中最復雜的是網絡部份,在實際的生產環境中更是如此,實際場景下往往不僅有Open stack網絡,還有外部網絡(Open

RestTemplate常見的請求方式

see 信息 book ren new 三個參數 body turn 表示 GET請求 第一種:getForEntity getForEntity方法的返回值是一個ResponseEntity<T>,ResponseEntity<T>是Spring對

Java呼叫sqlServer的儲存過程(CallableStatement)的簡單情況

一、呼叫不帶引數的儲存過程 --建立儲存過程 create procedure testselect as begin select bno from book; end package com.nc.dao; import java.sql.*; public class test

js常見的陣列迴圈

第一種:for迴圈 var arr = [1,2,3,4,5] for(var i=0;i<arr.length;i++){      console.log(arr[i]); //拿到每一個的值 } 第二種:for...in... v

Python常見方法實現斐波那契數列

Python常見斐波那契解決方案 n=35 #1.遞迴求斐波那契 def fibo(n): return 1 if n<3 else fibo(n-1)+fibo(n-2) print(fibo(n)) #2.迴圈求斐波那契 f1,f2=0,1 for i

javaMap在什麼情況下使用,並簡單介紹原因及原理

一、Map用於儲存具有對映關係的資料,Map裡儲存著兩組資料:key和value,它們都可以使任何引用型別的資料,但key不能重複。所以通過指定的key就可以取出對應的value。Map介面定義瞭如下常用的方法: 1、void clear():刪除Map中所以鍵值對。 2、b

java常見的排序演算法實現

在Java中得資料結構比較 | 資料機構 | 優點| 缺點 | |陣列 | 插入快,在直到下標得情況下可快速地存取| 查詢慢,刪除慢,大小固定 | |有序陣列 | 比無序得陣列查詢快|刪除和插入慢,大小固定 | |棧 | 提供後進先出方式的存取| 存取其他項很

解釋Java工程常見的包:PO,VO,DAO,BIZ,DTO,Service,ServiceImpl

一、PO:persistant object 持久物件,是與資料庫中的表相對映的java物件。最簡單的PO就是對應資料庫中某個表中的一條記錄,多個記錄可以用PO的集合。PO中應該不包含任何對資料庫的操作。  二、VO:value object值物件。通常用於業務層之間的資料傳

比較C#常見的複製位元組陣列方法的效率

        在日常程式設計過程中,我們可能經常需要Copy各種陣列,一般來說有以下幾種常見的方法:Array.Copy,IList<T>.Copy,BinaryReader.ReadBytes,Buffer.BlockCopy,以及System.Buffe

Java常見的編碼方式

幾種常見的編碼格式  為什麼要編碼  不知道大家有沒有想過一個問題,那就是為什麼要編碼?我們能不能不編碼?要回答這個問題必須要回到計算機是如何表示我們人類能夠理解的符號的,這些符號也就是我們人類使用的語言。由於人類的語言有太多,因而表示這些語言的符號太多,無法用計算機中一個基本的

C++常見的順序儲存結構

  C++中的容器類包括“順序儲存結構”和“關聯儲存結構”,前者包括vector,list,deque等;後者包括set,map,multiset,multimap等。若需要儲存的元素數在編譯器間就可以確定,可以使用陣列來儲存,否則,就需要用到容器類了。1、vector   

php常見安全設定詳解

php中幾種常見安全設定詳解  另外,目前鬧的轟轟烈烈的SQL Injection也是在PHP上有很多利用方式,所以要保證安全,PHP程式碼編寫是一方面,PHP的配置更是非常關鍵。 我們php手手工安裝的,php的預設配置檔案在 /usr/local/apache2/conf/ph

Java工程常見的包:PO,VO,DAO,BIZ,DTO,Service,ServiceImpl

一、PO:persistant object 持久物件,是與資料庫中的表相對映的Java物件。最簡單的PO就是對應資料庫中某個表中的一條記錄,多個記錄可以用PO的集合。PO中應該不包含任何對資料庫的操作。 二、VO:v

論OI常見的資料生成方法

零、前言 為了保證程式的正確,我們需要生成資料進行檢驗,這就需要使用到資料生成器. 本文就講講怎麼生成幾種OI中的常見資料. 一、排列 1、問題:給定N,在O(n)隨機出1—N的一個排列 2、STL 時間複雜度:O(N) 程式碼:

安卓常見對話方塊

AlertDialog dialog = null; private void showSetupPwdDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); View view = View.infla

java設計模式(單例模式,介面卡模式,簡單工廠模式)

1、單例模式:也分餓漢式單例模式(建立物件)與懶漢式單例模式(未建立物件)程式碼實現:餓漢式單例模式:懶漢式單例模式:2、介面卡模式:介面:實現介面的類:實現介面某個方法的類:3、簡單工廠模式:介面:類1:類2:工廠類:測試類: