AI 143894: am: CL 143890 Fixes #1749387. Improve the pooling of the VelocityTracker class. This introduces a new, hidden, API for pooling objects easily.

Original author: romainguy
  Merged from: //branches/donutburger/...

Automated import of CL 143894
This commit is contained in:
Romain Guy
2009-03-31 17:53:57 -07:00
committed by The Android Open Source Project
parent 2c62f84add
commit d1b3dd058d
8 changed files with 324 additions and 55 deletions

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
/**
* @hide
*/
class FinitePool<T extends Poolable<T>> implements Pool<T> {
/**
* Factory used to create new pool objects
*/
private final PoolableManager<T> mManager;
/**
* Maximum number of objects in the pool
*/
private final int mLimit;
/**
* If true, mLimit is ignored
*/
private final boolean mInfinite;
/**
* Next object to acquire
*/
private T mRoot;
/**
* Number of objects in the pool
*/
private int mPoolCount;
FinitePool(PoolableManager<T> manager) {
mManager = manager;
mLimit = 0;
mInfinite = true;
}
FinitePool(PoolableManager<T> manager, int limit) {
if (limit <= 0) throw new IllegalArgumentException("The pool limit must be > 0");
mManager = manager;
mLimit = limit;
mInfinite = false;
}
public T acquire() {
T element;
if (mRoot != null) {
element = mRoot;
mRoot = element.getNextPoolable();
mPoolCount--;
} else {
element = mManager.newInstance();
}
if (element != null) {
element.setNextPoolable(null);
mManager.onAcquired(element);
}
return element;
}
public void release(T element) {
if (mInfinite || mPoolCount < mLimit) {
mPoolCount++;
element.setNextPoolable(mRoot);
mRoot = element;
}
mManager.onReleased(element);
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
/**
* @hide
*/
public interface Pool<T extends Poolable<T>> {
public abstract T acquire();
public abstract void release(T element);
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
/**
* @hide
*/
public class PoolFactory {
private PoolFactory() {
}
public static <T extends Poolable<T>> Pool<T> simplePool(PoolableManager<T> manager) {
return new FinitePool<T>(manager);
}
public static <T extends Poolable<T>> Pool<T> finitePool(PoolableManager<T> manager, int limit) {
return new FinitePool<T>(manager, limit);
}
public static <T extends Poolable<T>> Pool<T> synchronizedPool(Pool<T> pool) {
return new SynchronizedPool<T>(pool);
}
public static <T extends Poolable<T>> Pool<T> synchronizedPool(Pool<T> pool, Object lock) {
return new SynchronizedPool<T>(pool, lock);
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
/**
* @hide
*/
public interface Poolable<T> {
void setNextPoolable(T element);
T getNextPoolable();
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
/**
* @hide
*/
public interface PoolableManager<T extends Poolable<T>> {
T newInstance();
void onAcquired(T element);
void onReleased(T element);
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.util;
/**
*
* @hide
*/
class SynchronizedPool<T extends Poolable<T>> implements Pool<T> {
private final Pool<T> mPool;
private final Object mLock;
public SynchronizedPool(Pool<T> pool) {
mPool = pool;
mLock = this;
}
public SynchronizedPool(Pool<T> pool, Object lock) {
mPool = pool;
mLock = lock;
}
public T acquire() {
synchronized (mLock) {
return mPool.acquire();
}
}
public void release(T element) {
synchronized (mLock) {
mPool.release(element);
}
}
}

View File

@@ -18,6 +18,10 @@ package android.view;
import android.util.Config;
import android.util.Log;
import android.util.Poolable;
import android.util.Pool;
import android.util.PoolFactory;
import android.util.PoolableManager;
/**
* Helper for tracking the velocity of touch events, for implementing
@@ -28,53 +32,72 @@ import android.util.Log;
* {@link #computeCurrentVelocity(int)} and then {@link #getXVelocity()}
* and {@link #getXVelocity()}.
*/
public final class VelocityTracker {
public final class VelocityTracker implements Poolable<VelocityTracker> {
static final String TAG = "VelocityTracker";
static final boolean DEBUG = false;
static final boolean localLOGV = DEBUG || Config.LOGV;
static final int NUM_PAST = 10;
static final int LONGEST_PAST_TIME = 200;
static final VelocityTracker[] mPool = new VelocityTracker[1];
private static final Pool<VelocityTracker> sPool = PoolFactory.synchronizedPool(
PoolFactory.finitePool(new PoolableManager<VelocityTracker>() {
public VelocityTracker newInstance() {
return new VelocityTracker();
}
public void onAcquired(VelocityTracker element) {
element.clear();
}
public void onReleased(VelocityTracker element) {
}
}, 2));
final float mPastX[] = new float[NUM_PAST];
final float mPastY[] = new float[NUM_PAST];
final long mPastTime[] = new long[NUM_PAST];
float mYVelocity;
float mXVelocity;
private VelocityTracker mNext;
/**
* Retrieve a new VelocityTracker object to watch the velocity of a
* motion. Be sure to call {@link #recycle} when done. You should
* generally only maintain an active object while tracking a movement,
* so that the VelocityTracker can be re-used elsewhere.
*
*
* @return Returns a new VelocityTracker.
*/
static public VelocityTracker obtain() {
synchronized (mPool) {
VelocityTracker vt = mPool[0];
if (vt != null) {
vt.clear();
mPool[0] = null;
return vt;
}
return new VelocityTracker();
}
return sPool.acquire();
}
/**
* Return a VelocityTracker object back to be re-used by others. You must
* not touch the object after calling this function.
*/
public void recycle() {
synchronized (mPool) {
mPool[0] = this;
}
sPool.release(this);
}
/**
* @hide
*/
public void setNextPoolable(VelocityTracker element) {
mNext = element;
}
/**
* @hide
*/
public VelocityTracker getNextPoolable() {
return mNext;
}
private VelocityTracker() {
}

View File

@@ -45,6 +45,10 @@ import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
import android.util.Poolable;
import android.util.Pool;
import android.util.PoolFactory;
import android.util.PoolableManager;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.animation.Animation;
import android.view.inputmethod.InputConnection;
@@ -7827,26 +7831,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* For performance purposes, this class also implements a pool of up to
* POOL_LIMIT objects that get reused. This reduces memory allocations
* whenever possible.
*
* The pool is implemented as a linked list of InvalidateInfo object with
* the root pointing to the next available InvalidateInfo. If the root
* is null (i.e. when all instances from the pool have been acquired),
* then a new InvalidateInfo is created and returned to the caller.
*
* An InvalidateInfo is sent back to the pool by calling its release()
* method. If the pool is full the object is simply discarded.
*
* This implementation follows the object pool pattern used in the
* MotionEvent class.
*/
static class InvalidateInfo {
static class InvalidateInfo implements Poolable<InvalidateInfo> {
private static final int POOL_LIMIT = 10;
private static final Object sLock = new Object();
private static final Pool<InvalidateInfo> sPool = PoolFactory.synchronizedPool(
PoolFactory.finitePool(new PoolableManager<InvalidateInfo>() {
public InvalidateInfo newInstance() {
return new InvalidateInfo();
}
private static int sAcquiredCount = 0;
private static InvalidateInfo sRoot;
public void onAcquired(InvalidateInfo element) {
}
private InvalidateInfo next;
public void onReleased(InvalidateInfo element) {
}
}, POOL_LIMIT)
);
private InvalidateInfo mNext;
View target;
@@ -7855,28 +7857,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
int right;
int bottom;
public void setNextPoolable(InvalidateInfo element) {
mNext = element;
}
public InvalidateInfo getNextPoolable() {
return mNext;
}
static InvalidateInfo acquire() {
synchronized (sLock) {
if (sRoot == null) {
return new InvalidateInfo();
}
InvalidateInfo info = sRoot;
sRoot = info.next;
sAcquiredCount--;
return info;
}
return sPool.acquire();
}
void release() {
synchronized (sLock) {
if (sAcquiredCount < POOL_LIMIT) {
sAcquiredCount++;
next = sRoot;
sRoot = this;
}
}
sPool.release(this);
}
}