diff options
author | Svetoslav Ganov <svetoslavganov@google.com> | 2012-11-27 16:59:37 -0800 |
---|---|---|
committer | Svetoslav Ganov <svetoslavganov@google.com> | 2012-11-27 19:10:51 -0800 |
commit | abae2a1b891772d36d8f781adfcc8969e551691f (patch) | |
tree | 361a160a5cb0e2e1fdbe8e27a57354152deb3d1f /core/java/android/util/Pools.java | |
parent | dccf9337e6c549cf0bf413dace0fee68589f628f (diff) | |
download | frameworks_base-abae2a1b891772d36d8f781adfcc8969e551691f.zip frameworks_base-abae2a1b891772d36d8f781adfcc8969e551691f.tar.gz frameworks_base-abae2a1b891772d36d8f781adfcc8969e551691f.tar.bz2 |
Simplification of the poolable management utils.
Before to implement a pool of objects, the pooled class had to implement an
interface which was leaking the pool management APIs. This requires
hiding APIs - inconvenient at best. Further, each client had to
implement the chaining of pooled instances which means adding a couple
of member variables which are manipulated by the implemented interface
methods. As a consequence the client is aware of how pooling is
implemented which is error prone and breaks encapsulation. Now the
pool objects are responsible for managing pooling state via reusable
wrapper objects and the clients are oblivious of how pooling is done.
Creating a thin cached wrapper for each pooled object has minimal
performance impact while making the code more maintainable. Actually
implementing of the old version of the APIs was taking as much code
as implementing the pooling yourself.
Also clients had to implement a poolable manager whose responsibility
was to create new instances and provide callbacks when an instance
is added to or removed from the pool. Now, the clinet class should
create a static member for the pool and expose obtain/aquire and
release/recycle methods in which it should create a new instance if
the pool did not return one and clear the state of the host when
it is returned to the pool. Updated the JavaDoc with a best practice.
The pooling was composed of several interfaces and classes scattered
over a few files, now all this is in a single small file.
Update all usages of the pooling APIs in the framework.
Also one had to write a poolable
manager which
Change-Id: Ib8dc286040eb3d7cb7d9668ba76fead05cb97647
Diffstat (limited to 'core/java/android/util/Pools.java')
-rw-r--r-- | core/java/android/util/Pools.java | 175 |
1 files changed, 164 insertions, 11 deletions
diff --git a/core/java/android/util/Pools.java b/core/java/android/util/Pools.java index 8edb3e6..908ede4 100644 --- a/core/java/android/util/Pools.java +++ b/core/java/android/util/Pools.java @@ -17,25 +17,178 @@ package android.util; /** + * Helper class for crating pools of objects. An example use looks like this: + * <pre> + * public class MyPooledClass { + * + * private static final Pool<MyPooledClass> sPool = + * new SynchronizedPool<MyPooledClass>(Pools.POOL_SIZE_INFINITE); + * + * public static MyPooledClass obtain() { + * MyPooledClass instance = sPool.acquire(); + * return (instance != null) ? instance : new MyPooledClass(); + * } + * + * public void recycle() { + * // Clear state if needed. + * sPool.release(this); + * } + * + * . . . + * } + * </pre> + * * @hide */ -public class Pools { - private Pools() { +public final class Pools { + + /** + * Pool with an infinite size. + */ + public static final int POOL_SIZE_INFINITE = -1; + + /** + * Interface for managing a pool of objects. + * + * @param <T> The pooled type. + */ + public static interface Pool<T> { + + /** + * @return An instance from the pool if such, null otherwise. + */ + public T acquire(); + + /** + * Release an instance to the pool. + * + * @param instance The instance to release. + * @return Whether the instance was put in the pool. + * + * @throws IllegalStateException If the instance is already in the pool. + */ + public boolean release(T instance); } - public static <T extends Poolable<T>> Pool<T> simplePool(PoolableManager<T> manager) { - return new FinitePool<T>(manager); + private Pools() { + /* do nothing - hiding constructor */ } - - public static <T extends Poolable<T>> Pool<T> finitePool(PoolableManager<T> manager, int limit) { - return new FinitePool<T>(manager, limit); + + private static class PoolableHolder<T> { + T mPoolable; + PoolableHolder<T> mNext; } - public static <T extends Poolable<T>> Pool<T> synchronizedPool(Pool<T> pool) { - return new SynchronizedPool<T>(pool); + /** + * Simple (non-synchronized) pool of objects. + * + * @param <T> The pooled type. + */ + public static class SimplePool<T> implements Pool<T> { + private final int mMaxPoolSize; + + private int mPoolSize; + + private PoolableHolder<T> mEmptyHolders; + private PoolableHolder<T> mPool; + + /** + * Creates a new instance. + * + * @param maxPoolSize The max pool size. + * + * @throws IllegalArgumentException If the max pool size is less than zero. + * + * @see Pools#POOL_SIZE_INFINITE + */ + public SimplePool(int maxPoolSize) { + if (maxPoolSize <= 0 && maxPoolSize != POOL_SIZE_INFINITE) { + throw new IllegalArgumentException("The max pool size must be > 0"); + } + mMaxPoolSize = maxPoolSize; + } + + @Override + public T acquire() { + if (mPool != null) { + PoolableHolder<T> holder = mPool; + mPool = holder.mNext; + T poolable = holder.mPoolable; + holder.mPoolable = null; + holder.mNext = mEmptyHolders; + mEmptyHolders = holder; + mPoolSize--; + return poolable; + } + return null; + } + + @Override + public boolean release(T instance) { + if (isInPool(instance)) { + throw new IllegalStateException("Already in the pool!"); + } + if (mMaxPoolSize == POOL_SIZE_INFINITE || mPoolSize < mMaxPoolSize) { + PoolableHolder<T> holder = mEmptyHolders; + if (holder == null) { + holder = new PoolableHolder<T>(); + } else { + mEmptyHolders = holder.mNext; + } + holder.mPoolable = instance; + holder.mNext = mPool; + mPool = holder; + mPoolSize++; + return true; + } + return false; + } + + private boolean isInPool(T instance) { + PoolableHolder<T> current = mPool; + while (current != null) { + if (current.mPoolable == instance) { + return true; + } + current = current.mNext; + } + return false; + } } - public static <T extends Poolable<T>> Pool<T> synchronizedPool(Pool<T> pool, Object lock) { - return new SynchronizedPool<T>(pool, lock); + /** + * Synchronized) pool of objects. + * + * @param <T> The pooled type. + */ + public static class SynchronizedPool<T> extends SimplePool<T> { + private final Object mLock = new Object(); + + /** + * Creates a new instance. + * + * @param maxPoolSize The max pool size. + * + * @throws IllegalArgumentException If the max pool size is less than zero. + * + * @see Pools#POOL_SIZE_INFINITE + */ + public SynchronizedPool(int maxPoolSize) { + super(maxPoolSize); + } + + @Override + public T acquire() { + synchronized (mLock) { + return super.acquire(); + } + } + + @Override + public boolean release(T element) { + synchronized (mLock) { + return super.release(element); + } + } } } |