天天看點

Android ListView 優化

一.item 的layout中盡量避免使用wrap_content ,可以使用固定的dp/dip,或者fill_parent/match_parent ; View在Draw的時候分成兩個階段:measure和layout,在measure階段時主要就是為了計算兩個參數:height和width。而且要注意的是,這是個遞歸的過程,從頂向下,DecorView開始依次調用自己子元素的measure。計算完成這兩個參數後就開始layout,最後再是draw的調用。 wrap_content 要計算自己的大小,fill_parent填充父view給的大小,減少了計算。

對于ListView,當然每一個Item都會被調用measure方法,而在這個過程中getView和getCount會被調用,根據操作,可能會有很多次調用。

二.Doesn't show fading edges.

三.注意adapter中getview裡面的緩存處理。利用convertview回收視圖,效率提高200%。利用viewholder模式,效率在提高50%。

1. ListView需要設定adapter,它的item是通過adapter的方法getView(int position, View convertView, ViewGroup parent)獲得的。

2. ListView中隻有第一屏的item需要建立,它的引用會被存在RecycleBin對象内,在拖動時後面的item實際上是重從了之前建立的item。

3. 根據上述,ListView在需要顯示item時,最開始第一屏時,getView(int position, View convertView, ViewGroupparent )的第二個參數為null,顯示第二屏或者復原顯示第一屏時,getView(int position, View convertView, ViewGroupparent )第二個參數是一個原來緩存的item,我們隻需要在getView中把它内部資料更新即可。

4. 如果item結構比較複雜,在更新一個已有的item内部資料的時候,查找item内部每一個元素也需要占用不少資源,是以,可以把這些内部元素的引用緩存起來,直接對其指派,最有效的方法是把這些引用存到對應的item中,比較好的方法是使用setTag()方法。

據上四條,可得出:

1. 在adapter的getView(int position, View convertView, ViewGroup parent)方法中,每次都new一個新的View傳回,是性能最差的,浪費了ListView巧妙設計的一片苦心。

2. 如果item内部元素簡單,getView中如果傳進來的view不為空,直接為其指派即可。

3. 如果item内部元素複雜,可以使用Google IO 大會中讨論的方法優化(如下):

public View getView(int position, View convertView, ViewGroup parent) {       

    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);

            convertView.setTag(holder);

    }

    else{

           holder = (ViewHolder)convertView.getTag();

    }

        holder.icon1.setImageResource(R.drawable.icon);

        holder.text1.setText(mData[position]);

        return convertView;

}

static class ViewHolder {

        TextView text1;

        ImageView icon1;

}

四.簡化視圖和布局

如果一個視窗包含很多視圖,啟動太慢,繪制時間長,使用者界面反應速度很慢,解決方法:

1。使用textview的複合drawable減少層次

<TextView

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/hello"

android:drawableLeft="@drawable/icon"/>

2。使用viewstuf延遲展開視圖

  在xml檔案中定義viewstuf

<ViewStub android:id = "@+id/stub_import"

android:inflatedId="@+id/panel_import"

android:layout="@layout/progress_overlay"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:layout_gravity="bottom"/>

  在需要展開視圖時,

findViewById(R.id.stub_import).setVisibility(View.VISIBLE);

// 或者

View importPanel = ((ViewStub)

findViewById(R.id.stub_import)).inflate();

3。使用<merge>合并中間視圖  

預設情況下,布局檔案的根作為一個節點,加入到父視圖中,如果使用merge可以避免根節點

<merge xmlns:android = "http://schemas.android.com/apk/res/android">

<! -- Content -->

</merge>

4。使用ralativelayout減少層次

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent" android:layout_height="wrap_content">

<ImageView android:id="@+id/icon"

android:layout_width="48dip" android:layout_height="48dip"

android:layout_alignParentLeft="true"

android:layout_centerVertical="true"/>

<TextView android:layout_width="wrap_content"

android:layout_height="wrap_content" android:id="@+id/text_line1"

android:layout_alignParentTop="true"

android:layout_toRightOf="@id/icon"/>

<TextViewandroid:layout_width="wrap_content"

android:layout_height="wrap_content" android:id="@+id/text_line2"

android:layout_toRightOf="@id/icon"

android:layout_below="@id/text_line1"/>

<Checkbox android:id="@+id/star"

android:layout_width="48dip" android:layout_height="48dip"

android:layout_alignParentRight="true"

android:layout_centerVertical="true"/>

</RelativeLayout>

5.使用自定義視圖

class CustomView extends View {

@Override

protected void onDraw(Canvascanvas) {

// 加入你的繪圖編碼

}

@Override

protected void onMeasure(int widthMeasureSpec,

int heightMeasureSpec) {

// 計算視圖的尺寸

setMeasuredDimension(widthSpecSize, heightSpecSize);

}

}

6 使用自定義布局

class GridLayout extends ViewGroup {

@Override

protected void onLayout(boolean changed, int l, int t,

int r, int b) {

final int count =getChildCount();

for (int i=0; i <count; i++) {

final View child = getChildAt(i);

if (child.getVisibility() !=GONE) {

// 計算子視圖的位置

child.layout(left, top, right, bottom);

}

}

}

}

五.更新看不見的背景是浪費時間,可設定相關控件背景為空

1。代碼設定

public void onCreate(Bundleicicle){

super.onCreate(icicle);

setContentView(R.layout.mainview);

// 删除視窗背景

getWindow().setBackgroundDrawable(null);

...

2。Xml設定

首先确定你的res/values/styles.xml有

<resources>

<style name="NoBackgroundTheme" parent="android:Theme">

<itemname="android:windowBackground">@null</item>

</style>

</resources>

然後編輯androidmainfest.xml

<activity android:name="MyApplication"

android:theme="@style/NoBackgroundTheme">

...

</activity>

六.控制記憶體配置設定

在性能敏感的代碼裡,避免建立java對象:

1。測量 onmeasure()

2。布局onlayout()

3。繪圖 ondraw() dispatchdraw()

4。事件處理 ontouchevent() dispatchtouchevent()

5。adapter: getview() bindview()

在調試模式下進行強行限制

int prevLimit = -1;

try {

prevLimit = Debug.setAllocationLimit(0);

// 執行不配置設定記憶體的代碼

} catch (dalvik.system.AllocationLimitErrore) {

// 如果代碼配置設定記憶體, Java 虛拟機會抛出錯誤

Log.e(LOGTAG, e);

} finally {

Debug.setAllocationLimit(prevLimit);

}

管理好對象:

1。适用軟引用:記憶體緩存的最佳選擇

2。适用弱引用:避免記憶體洩露

private final HashMap<String,SoftReference<T>> mCache;

public void put(Stringkey, T value) {

mCache.put(key, new SoftReference<T>(value));

}

public T get(String key, ValueBuilderbuilder) {

T value = null;

SoftReferece<T> reference = mCache.get(key);

if (reference != null) {

value = reference.get();

參考過幾篇博文,自己也試用過的一些方法。特此整理,亦可參考http://edu.gamfe.com/tutor/d/30509.html等有樣例測試的文章。