標籤:
ListView的最佳化
- 複用convertview , 曆史的view對象
- 減少子孩子查詢的次數 viewholder
- 非同步載入資料(把圖片緩衝)
- 條目多時分頁載入資料
載入時顯示進度條讓使用者等待
Item的布局階層盡量簡單,避免布局太深或者不必要的重繪
避免在 getView 方法中做耗時的操作:
例如載入本地 Image 需要載入記憶體以及解析 Bitmap ,都是比較耗時的操作,如果使用者快速滑動listview,會因為getview邏輯過於複雜耗時而造成滑動卡頓現象。使用者滑動時候不要載入圖片,待滑動完成再載入,可以使用這個第三方庫glide
- 應該盡量避免 static 成員變數引用資源耗費過多的執行個體,比如 Context。
盡量使用 getApplicationContext:如果為了滿足需求下必須使用 Context 的話:Context 盡量使用 Application Context,因為Application 的 Context 的生命週期比較長,引用它不會出現記憶體泄露的問題
在一些情境中,ScollView內會包含多個ListView,可以把listview的高度寫死固定下來。
由於ScollView在快速滑動過程中需要大量計算每一個listview的高度,阻塞了UI線程導致卡頓現象出現,如果我們每一個item的高度都是均勻的,可以通過計算把listview的高度確定下來,避免卡頓現象出現
使用 RecycleView 代替listview:
每個item內容的變動,listview都需要去調用notifyDataSetChanged來更新全部的item,太浪費效能了。RecycleView可以實現當個item的局部重新整理,並且引入了增加和刪除的動態效果,在效能上和定製上都有很大的改善
ListView 中元素避免半透明:
半透明繪製需要大量乘法計算,在滑動時不停重繪會造成大量的計算,在比較差的機子上會比較卡。 在設計上能不半透明就不不半透明。實在要弄就把在滑動的時候把半透明設定成不透明,滑動完再重新設定成半透明。
盡量開啟硬體加速:
硬體加速提升巨大,避免使用一些不支援的函數導致含淚關閉某個地方的硬體加速。當然這一條不只是對 ListView。
布局的最佳化
- 盡量重用一個布局檔案,使用include標籤,多個相同的布局可以複用
- 減少一個布局的不必要節點
- 盡量使用view自身的參數,例如:Button,有一個可以把圖繪製在左邊的參數:android:drawableLeft
- 使用< ViewStub />標籤來載入一些不常用的布局;使用< merge />標籤減少布局的嵌套層次
viewPager的最佳化
- viewpager會預設載入左右倆個頁面,有時候我們並不想看,會浪費使用者的流量,可以在setOnPageChangeListener的onPageSelected的方法裡選中哪個頁面,初始化哪個頁面
- 由於viewpager會預設銷毀第三頁面,可以強制讓viewpager載入所有的頁面pagerView.setOffscreenPageLimit(pageCount);,但是如果頁面多的話就不能這樣幹了
- 可以定義一個集合將頁面緩衝起來,在destroyItem的時候儲存起來,在instantiateItem讀取集合,有就用,沒有的話再建立,就像listview的convertView似的
class HomeAdapter extends PagerAdapter {// 當前viewPager裡面有多少個條目LinkedList<ImageView> convertView=new LinkedList<ImageView>();@Overridepublic int getCount() {returnInteger.MAX_VALUE;}/* 判斷返回的對象和 載入view對象的關係 */@Overridepublic boolean isViewFromObject(View arg0, Object arg1) {return arg0 == arg1;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {ImageView view=(ImageView) object;convertView.add(view);// 把移除的對象 添加到緩衝集合中container.removeView(view);}@Overridepublic Object instantiateItem(ViewGroup container, int position) {ImageView view;if(convertView.size()>0){view=convertView.remove(0);}else{view= new ImageView(UiUtils.getContext());}bitmapUtils.display(view, HttpHelper.URL + "image?name="+ datas.get(index));container.addView(view); // 載入的view對象return view; // 返回的對象}}
記憶體的最佳化
- 回收已經使用的資源,比如遊標cursor 、I/O、Bitmap(close並且引用置為null)
- 合理的使用緩衝,比片是很耗記憶體的,使用lru緩衝圖片和壓縮
- 合理設定變數的作用範圍
- 節制的使用服務,背景工作運行完,即使它不執行任何操作,服務也會一直運行,這些是十分消耗記憶體的,可以用intentservice
- 當介面不可見時釋放記憶體,在activity的onTrimMemory方法裡與ui的相關資源,在onstop裡釋放與組件相關的資源
- 合理的使用多進程,如果背景工作和前台介面是相互獨立在,可以在組件標籤下寫process,這樣這個組建就在另一個進程裡了。而服務的話更傾向於開啟自己所依賴的進城,而那個進程可能很多東西都不需要,比如ui
- 使用線程池、對象池
- Bitmap對象在不使用時,應該先調用recycle()釋放記憶體,然後才它設定為null。
代碼最佳化
這部分就是是細微的最佳化,但是細微多了也就記憶體節約了
任何一個Java類,包括內部類、匿名類,都要佔用大概500位元組的記憶體空間。
任何一個類的執行個體要消耗12-16位元組的記憶體開支,因此頻繁建立執行個體也是會一定程式上影響記憶體的,所以要避免建立不必要的對象
- 如果有一個需要拼接的字串,那麼可以優先考慮使用StringBuffer或者StringBuilder來進行拼接,而不是加號串連符,因為使用加號串連符會建立多餘的對象,拼接的字串越長,加號串連符的效能越低
- 盡量使用基本資料類來代替封裝資料類型,int比Integer要更加高效,其它資料類型也是一樣
使用靜態
- 使用枚舉通常會比使用靜態常量要消耗兩倍以上的記憶體,在Android開發當中應當儘可能地不使用枚舉。
- 如果你並不需要訪問一個對象中的某些欄位,只是想調用它的某個方法來去完成一項通用的功能,那麼可以將這個方法設定成靜態方法,這會讓調用的速度提升15%-20%,同時也不用為了調用這個方法而去專門建立對象了,這樣還滿足了上面的一條原則。另外這也是一種好的編程習慣,因為我們可以放心地調用靜態方法,而不用擔心調用這個方法後是否會改變對象的狀態(靜態方法內無法訪問非靜態欄位)
對常量使用static final修飾符
使用增強型for迴圈文法
多使用系統封裝好的API,比如:indexOf(),System.arraycopy()
效能最佳化:盡量使用drawable對象儲存圖片而不是bitmap
drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");
ui組件需要用到的圖片是apk包內建的,那麼一律用setImageResource或者setBackgroundResource,而不要根據resourceid
注意:get(getResources(),R.drawable.btn_achievement_normal)該方法通過resid轉換為drawable,需要考慮回收的問題,如果drawable是對象私人對象,在對象銷毀前是肯定不會釋放記憶體的。
Android最佳化指南