文章目錄
-
- 概述
- Android Object Pools
-
-
- Pools源碼解析:
- Pools結合Builder模式使用案例:
-
- 使用總結和注意事項
概述
由記憶體優化(一)淺談記憶體優化中看出,記憶體優化不僅要從防止記憶體洩露入手,也要注意頻繁GC卡頓,記憶體抖動以及不必要的記憶體開銷造成的記憶體需求過大或者記憶體洩露。而避免記憶體無用開銷就必須了解Android開發中的一個重要原則——對象複用。
對象複用在我們開發中使用的案例很多,Adapter就是這個原則的着重展現。本文主要寫的是Android對象池的使用,在一些請求架構中可能會用到,頻繁建立Request Bean對象,這時,對象池就顯得尤為重要了,它能很好的複用對象,避免頻繁建立和銷毀。
Android Object Pools
Android對象池是由Android源碼中提供的一個類:
android.support.v4.util.Pools
,正常的使用對象池我們都可以通過它實作,它的源碼也很簡單,如下:
Pools源碼解析:
- Pools中主要實作2個接口:acquire(從池中擷取對象),release(釋放對象,存入池中)
- 2個内部類,分别是SimplePool和SynchronizedPool,SynchronizedPool是繼承SimplePool,裡面通過Synchronized同步鎖實作一個安全的對象池
- Pools通過維持一個對象數組,存入複用對象,當數組滿了便隻能建立新的對象
- Pools有個很好的特點:它并不需要預先建立對象到對象池,它需要在release方法中将回收對象添加到複用的對象池中
public final class Pools { public interface Pool<T> { /** * 擷取對象 */ @Nullable T acquire(); /** *釋放對象 */ boolean release(@NonNull T instance); } private Pools() { /* do nothing - hiding constructor */ } /** * 非同步對象池. */ public static class SimplePool<T> implements Pool<T> { private final Object[] mPool; private int mPoolSize; /** * 建立一個對象池,并指定最大存入對象數量 */ public SimplePool(int maxPoolSize) { if (maxPoolSize <= 0) { throw new IllegalArgumentException("The max pool size must be > 0"); } mPool = new Object[maxPoolSize]; } @Override @SuppressWarnings("unchecked") public T acquire() { if (mPoolSize > 0) { final int lastPooledIndex = mPoolSize - 1; T instance = (T) mPool[lastPooledIndex]; mPool[lastPooledIndex] = null; mPoolSize--; return instance; } return null; } @Override public boolean release(@NonNull T instance) { if (isInPool(instance)) { throw new IllegalStateException("Already in the pool!"); } if (mPoolSize < mPool.length) { mPool[mPoolSize] = instance; mPoolSize++; return true; } return false; } private boolean isInPool(@NonNull T instance) { for (int i = 0; i < mPoolSize; i++) { if (mPool[i] == instance) { return true; } } return false; } } /** * 同步對象池 */ public static class SynchronizedPool<T> extends SimplePool<T> { private final Object mLock = new Object(); public SynchronizedPool(int maxPoolSize) { super(maxPoolSize); } @Override public T acquire() { //通過synchronized實作同步 synchronized (mLock) { return super.acquire(); } } @Override public boolean release(@NonNull T element) { synchronized (mLock) { return super.release(element); } } } }
Pools結合Builder模式使用案例:
- 建立一個請求對象,當參數較多時結合Builder模式一起使用:
CtlRequestObj builder = new CtlRequestObj.Builder().setCmd(1).setState(0).setParam(2).builder();
- CtlRequestObj :
/** * Created by Felix on 15/12/12. */ public class CtlRequestObj { private int cmd; private int param; private int state; public int getCmd() { return cmd; } public void setCmd(int cmd) { this.cmd = cmd; } public int getParam() { return param; } public void setParam(int param) { this.param = param; } public int getState() { return state; } public void setState(int state) { this.state = state; } private CtlRequestObj() { } /** * 初始化對象狀态 */ private void releaseConfig() { cmd = 0; param = 0; state = 0; } /** * 回收對象:初始化對象-->存入對象池 */ public void recycle() { // Clear state if needed. this.releaseConfig(); sPool.release(this); } //初始化線程池 private static final Pools.SimplePool<CtlRequestObj> sPool = new Pools.SimplePool<CtlRequestObj>(Constants.CTR_REQUEST_BEANS_SPOOL_SIZE); /** * 擷取(建立對象) * 預設從對象池中擷取,拿不到就new * * @return */ public static CtlRequestObj obtain() { CtlRequestObj instance = sPool.acquire(); return (instance != null) ? instance : new CtlRequestObj(); } /** * 通過Builder模式建立 */ public static class Builder { private int cmd; private int param; private int state; public Builder() { } public CtlRequestObj.Builder setCmd(int cmd) { this.cmd = cmd; return this; } public CtlRequestObj.Builder setState(int state) { this.state = state; return this; } public CtlRequestObj.Builder setParam(int param) { this.param = param; return this; } private void applyConfig(CtlRequestObj config) { config.cmd = this.cmd; config.param = this.param; config.state = this.state; } public CtlRequestObj builder() { CtlRequestObj obtain = CtlRequestObj.obtain(); applyConfig(obtain); return obtain; } } }
使用總結和注意事項
Android對象池的源碼非常簡單,我們能夠自己封裝也能自己去實作,對象池的應用很廣泛,比如Message和Glide中都有用到。我們自己在使用中,大部分簡單的使用都可以通過Android提供的SimplePool和SynchronizedPool去實作,但是它也有弊端,對象池沒有最終銷毀機制,是以我們如果使用應該注意銷毀對象池。
應該需要的注意點:
- recycle對象時注意清空對象的變量
- 當對象池滿時,擷取對象便隻能通過new對象擷取,是以應該注意對象大小設定
- 當長時間不使用對象池時應該注意銷毀對象池
public void destoryPool() { if (sPool != null) { sPool = null; } }