diff options
author | Xavier Ducrohet <xav@android.com> | 2011-02-22 11:54:37 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2011-02-23 12:00:41 -0800 |
commit | cc4977d0fdaf657907912fd6cc2f9426dc8d2e36 (patch) | |
tree | a49b4d71fa36d705dd6659f872bb8339fc357825 | |
parent | 8cb6fc184dcb9cc6ab0871de5cf430277d15c8c8 (diff) | |
download | frameworks_base-cc4977d0fdaf657907912fd6cc2f9426dc8d2e36.zip frameworks_base-cc4977d0fdaf657907912fd6cc2f9426dc8d2e36.tar.gz frameworks_base-cc4977d0fdaf657907912fd6cc2f9426dc8d2e36.tar.bz2 |
LayoutLib: Hold onto delegate references.
When an object is given a delegate to hold onto, keep
the reference to the delegate instead of its native integer.
Also change the way the finalizer works by not explicitely deleting
the delegate. Instead we want the delegate to be deleted when
nothing holds a reference to it. To do this, instead of using
a regular SparseArray, we use a SparseArray of WeakReferences.
Because the main Java object that "owns" the delegate does not
actually holds a reference to the delegate, we fake this by
having the delegate manager hold a reference to delegates for
the main object. This is added/removed as the object is created
and the native finalized is called.
This makes layoutlib behave more like the JNI code where the native
objects are reference counted, and where the Java object can be
deleted but the delegate it owns is kept around (usually because
another type of delegates hold a reference on it.)
To properly handle the WeakReferences, we need to be able to
regularly clear the SparseArray of WeakReference that were
referencing objects that have been GC'ed.
Since the SparseArray is regularly being compacted (actually only
when items are removed), we use a custom SparseWeakArray (started
as a straight copy of SparseArray) that handles the WeakReference
and takes care of compacting the array by removing deleted indices
and WeakReference that returns null. Since our specific use case
doesn't call actually delete() or remove(), the compacting
only happens when the array needs to be resized.
Change-Id: Iacc5c1ff5b21732b8816fda87eb090da12d034e0
37 files changed, 200 insertions, 141 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java index e193477..a50a2bd 100644 --- a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java @@ -63,7 +63,7 @@ public class AvoidXfermode_Delegate extends Xfermode_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(int opColor, int tolerance, int nativeMode) { AvoidXfermode_Delegate newDelegate = new AvoidXfermode_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java index c6fde7b..9a8cf04 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java @@ -76,7 +76,7 @@ public class BitmapShader_Delegate extends Shader_Delegate { bitmap.getImage(), Shader_Delegate.getTileMode(shaderTileModeX), Shader_Delegate.getTileMode(shaderTileModeY)); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index 0c87766..b6d5725 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -245,12 +245,12 @@ public final class Bitmap_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int nativeBitmap) { - sManager.removeDelegate(nativeBitmap); + sManager.removeJavaReferenceFor(nativeBitmap); } @LayoutlibDelegate /*package*/ static void nativeRecycle(int nativeBitmap) { - sManager.removeDelegate(nativeBitmap); + sManager.removeJavaReferenceFor(nativeBitmap); } @LayoutlibDelegate @@ -522,7 +522,7 @@ public final class Bitmap_Delegate { private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) { // get its native_int - int nativeInt = sManager.addDelegate(delegate); + int nativeInt = sManager.addNewDelegate(delegate); // and create/return a new Bitmap with it return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/, density); diff --git a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java index 92d0d0a..4becba1 100644 --- a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java @@ -57,7 +57,7 @@ public class BlurMaskFilter_Delegate extends MaskFilter_Delegate { @LayoutlibDelegate /*package*/ static int nativeConstructor(float radius, int style) { BlurMaskFilter_Delegate newDelegate = new BlurMaskFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index e8a99b5..b657caf 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -64,7 +64,7 @@ public final class Canvas_Delegate { private Bitmap_Delegate mBitmap; private GcSnapshot mSnapshot; - private int mDrawFilter = 0; + private DrawFilter_Delegate mDrawFilter = null; // ---- Public Helper methods ---- @@ -95,7 +95,7 @@ public final class Canvas_Delegate { * @return the delegate or null. */ public DrawFilter_Delegate getDrawFilter() { - return DrawFilter_Delegate.getDelegate(mDrawFilter); + return mDrawFilter; } // ---- native methods ---- @@ -313,12 +313,12 @@ public final class Canvas_Delegate { // create a new Canvas_Delegate with the given bitmap and return its new native int. Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } else { // create a new Canvas_Delegate and return its new native int. Canvas_Delegate newDelegate = new Canvas_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } } @@ -510,26 +510,18 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - /*package*/ static void nativeSetDrawFilter(int nativeCanvas, - int nativeFilter) { + /*package*/ static void nativeSetDrawFilter(int nativeCanvas, int nativeFilter) { Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; } - canvasDelegate.mDrawFilter = nativeFilter; + canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter); - // get the delegate only because we don't support them at all for the moment, so - // we can display the message now. - - DrawFilter_Delegate filterDelegate = DrawFilter_Delegate.getDelegate(nativeFilter); - if (canvasDelegate == null) { - return; - } - - if (filterDelegate.isSupported() == false) { + if (canvasDelegate.mDrawFilter != null && + canvasDelegate.mDrawFilter.isSupported() == false) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER, - filterDelegate.getSupportMessage(), null, null /*data*/); + canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/); } } @@ -1139,7 +1131,7 @@ public final class Canvas_Delegate { canvasDelegate.dispose(); // remove it from the manager. - sManager.removeDelegate(nativeCanvas); + sManager.removeJavaReferenceFor(nativeCanvas); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java index 789c6e6..e786eb5 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java @@ -57,7 +57,7 @@ public abstract class ColorFilter_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int native_instance, int nativeColorFilter) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java index 462b1e6..2de344b 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java @@ -57,7 +57,7 @@ public class ColorMatrixColorFilter_Delegate extends ColorFilter_Delegate { @LayoutlibDelegate /*package*/ static int nativeColorMatrixFilter(float[] array) { ColorMatrixColorFilter_Delegate newDelegate = new ColorMatrixColorFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java index 2bdaa5b..7c04a87 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java @@ -64,7 +64,7 @@ public class ComposePathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(int outerpe, int innerpe) { ComposePathEffect_Delegate newDelegate = new ComposePathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java index a2ecb8f..f6e1d00 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java @@ -67,7 +67,7 @@ public class ComposeShader_Delegate extends Shader_Delegate { int native_mode) { // FIXME not supported yet. ComposeShader_Delegate newDelegate = new ComposeShader_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -75,7 +75,7 @@ public class ComposeShader_Delegate extends Shader_Delegate { int porterDuffMode) { // FIXME not supported yet. ComposeShader_Delegate newDelegate = new ComposeShader_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java index c677de8..b0f8168 100644 --- a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java @@ -64,7 +64,7 @@ public class CornerPathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(float radius) { CornerPathEffect_Delegate newDelegate = new CornerPathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java index 12a4d4a..d97c2ec 100644 --- a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java @@ -75,7 +75,7 @@ public final class DashPathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(float intervals[], float phase) { DashPathEffect_Delegate newDelegate = new DashPathEffect_Delegate(intervals, phase); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java index ac69712..ec4a810 100644 --- a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java @@ -64,7 +64,7 @@ public class DiscretePathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(float length, float deviation) { DiscretePathEffect_Delegate newDelegate = new DiscretePathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java index a98f0a9..37c7359 100644 --- a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java @@ -57,7 +57,7 @@ public abstract class DrawFilter_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int nativeDrawFilter) { - sManager.removeDelegate(nativeDrawFilter); + sManager.removeJavaReferenceFor(nativeDrawFilter); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java index 31f8bbf..ebc1c1d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java @@ -58,7 +58,7 @@ public class EmbossMaskFilter_Delegate extends MaskFilter_Delegate { /*package*/ static int nativeConstructor(float[] direction, float ambient, float specular, float blurRadius) { EmbossMaskFilter_Delegate newDelegate = new EmbossMaskFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java index fcb62a8..51e0576 100644 --- a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java @@ -57,7 +57,7 @@ public class LayerRasterizer_Delegate extends Rasterizer_Delegate { @LayoutlibDelegate /*package*/ static int nativeConstructor() { LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java index b272534..0ee883d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java @@ -57,7 +57,7 @@ public class LightingColorFilter_Delegate extends ColorFilter_Delegate { @LayoutlibDelegate /*package*/ static int native_CreateLightingFilter(int mul, int add) { LightingColorFilter_Delegate newDelegate = new LightingColorFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java index 8060577..a2ba758 100644 --- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java @@ -59,7 +59,7 @@ public final class LinearGradient_Delegate extends Gradient_Delegate { int colors[], float positions[], int tileMode) { LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(x0, y0, x1, y1, colors, positions, Shader_Delegate.getTileMode(tileMode)); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java index 4adca27..5a6167d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java @@ -57,7 +57,7 @@ public abstract class MaskFilter_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int native_filter) { - sManager.removeDelegate(native_filter); + sManager.removeJavaReferenceFor(native_filter); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java index 68a476f..251aa16 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java @@ -189,7 +189,7 @@ public final class Matrix_Delegate { } } - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -765,7 +765,7 @@ public final class Matrix_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int native_instance) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } // ---- Private helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java index dfcb591..71d346a 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java @@ -57,7 +57,7 @@ public class PaintFlagsDrawFilter_Delegate extends DrawFilter_Delegate { @LayoutlibDelegate /*package*/ static int nativeConstructor(int clearBits, int setBits) { PaintFlagsDrawFilter_Delegate newDelegate = new PaintFlagsDrawFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index f5d2547..74a9124 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -75,19 +75,19 @@ public class Paint_Delegate { private int mCap; private int mJoin; private int mTextAlign; - private int mTypeface; + private Typeface_Delegate mTypeface; private float mStrokeWidth; private float mStrokeMiter; private float mTextSize; private float mTextScaleX; private float mTextSkewX; - private int mXfermode; - private int mColorFilter; - private int mShader; - private int mPathEffect; - private int mMaskFilter; - private int mRasterizer; + private Xfermode_Delegate mXfermode; + private ColorFilter_Delegate mColorFilter; + private Shader_Delegate mShader; + private PathEffect_Delegate mPathEffect; + private MaskFilter_Delegate mMaskFilter; + private Rasterizer_Delegate mRasterizer; // ---- Public Helper methods ---- @@ -172,17 +172,16 @@ public class Paint_Delegate { } public Stroke getJavaStroke() { - PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect); - if (effectDelegate != null) { - if (effectDelegate.isSupported()) { - Stroke stroke = effectDelegate.getStroke(this); + if (mPathEffect != null) { + if (mPathEffect.isSupported()) { + Stroke stroke = mPathEffect.getStroke(this); assert stroke != null; if (stroke != null) { return stroke; } } else { Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT, - effectDelegate.getSupportMessage(), + mPathEffect.getSupportMessage(), null, null /*data*/); } } @@ -201,7 +200,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public Xfermode_Delegate getXfermode() { - return Xfermode_Delegate.getDelegate(mXfermode); + return mXfermode; } /** @@ -210,7 +209,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public ColorFilter_Delegate getColorFilter() { - return ColorFilter_Delegate.getDelegate(mColorFilter); + return mColorFilter; } /** @@ -219,7 +218,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public Shader_Delegate getShader() { - return Shader_Delegate.getDelegate(mShader); + return mShader; } /** @@ -228,7 +227,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public MaskFilter_Delegate getMaskFilter() { - return MaskFilter_Delegate.getDelegate(mMaskFilter); + return mMaskFilter; } /** @@ -237,7 +236,7 @@ public class Paint_Delegate { * @return the delegate or null. */ public Rasterizer_Delegate getRasterizer() { - return Rasterizer_Delegate.getDelegate(mRasterizer); + return mRasterizer; } // ---- native methods ---- @@ -585,7 +584,7 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static int native_init() { Paint_Delegate newDelegate = new Paint_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -597,7 +596,7 @@ public class Paint_Delegate { } Paint_Delegate newDelegate = new Paint_Delegate(delegate); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -728,7 +727,9 @@ public class Paint_Delegate { return shader; } - return delegate.mShader = shader; + delegate.mShader = Shader_Delegate.getDelegate(shader); + + return shader; } @LayoutlibDelegate @@ -739,13 +740,12 @@ public class Paint_Delegate { return filter; } - delegate.mColorFilter = filter; + delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);; // since none of those are supported, display a fidelity warning right away - ColorFilter_Delegate filterDelegate = delegate.getColorFilter(); - if (filterDelegate != null && filterDelegate.isSupported() == false) { + if (delegate.mColorFilter != null && delegate.mColorFilter.isSupported() == false) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER, - filterDelegate.getSupportMessage(), null, null /*data*/); + delegate.mColorFilter.getSupportMessage(), null, null /*data*/); } return filter; @@ -759,7 +759,9 @@ public class Paint_Delegate { return xfermode; } - return delegate.mXfermode = xfermode; + delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode); + + return xfermode; } @LayoutlibDelegate @@ -770,7 +772,9 @@ public class Paint_Delegate { return effect; } - return delegate.mPathEffect = effect; + delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect); + + return effect; } @LayoutlibDelegate @@ -781,13 +785,12 @@ public class Paint_Delegate { return maskfilter; } - delegate.mMaskFilter = maskfilter; + delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter); // since none of those are supported, display a fidelity warning right away - MaskFilter_Delegate filterDelegate = delegate.getMaskFilter(); - if (filterDelegate != null && filterDelegate.isSupported() == false) { + if (delegate.mMaskFilter != null && delegate.mMaskFilter.isSupported() == false) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER, - filterDelegate.getSupportMessage(), null, null /*data*/); + delegate.mMaskFilter.getSupportMessage(), null, null /*data*/); } return maskfilter; @@ -801,9 +804,9 @@ public class Paint_Delegate { return 0; } - delegate.mTypeface = typeface; + delegate.mTypeface = Typeface_Delegate.getDelegate(typeface); delegate.updateFontObject(); - return delegate.mTypeface; + return typeface; } @LayoutlibDelegate @@ -814,13 +817,12 @@ public class Paint_Delegate { return rasterizer; } - delegate.mRasterizer = rasterizer; + delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer); // since none of those are supported, display a fidelity warning right away - Rasterizer_Delegate rasterizerDelegate = delegate.getRasterizer(); - if (rasterizerDelegate != null && rasterizerDelegate.isSupported() == false) { + if (delegate.mRasterizer != null && delegate.mRasterizer.isSupported() == false) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER, - rasterizerDelegate.getSupportMessage(), null, null /*data*/); + delegate.mRasterizer.getSupportMessage(), null, null /*data*/); } return rasterizer; @@ -986,7 +988,7 @@ public class Paint_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int nativePaint) { - sManager.removeDelegate(nativePaint); + sManager.removeJavaReferenceFor(nativePaint); } // ---- Private delegate/helper methods ---- @@ -1028,18 +1030,18 @@ public class Paint_Delegate { mCap = Paint.Cap.BUTT.nativeInt; mJoin = Paint.Join.MITER.nativeInt; mTextAlign = 0; - mTypeface = Typeface.sDefaults[0].native_instance; + mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance); mStrokeWidth = 1.f; mStrokeMiter = 4.f; mTextSize = 20.f; mTextScaleX = 1.f; mTextSkewX = 0.f; - mXfermode = 0; - mColorFilter = 0; - mShader = 0; - mPathEffect = 0; - mMaskFilter = 0; - mRasterizer = 0; + mXfermode = null; + mColorFilter = null; + mShader = null; + mPathEffect = null; + mMaskFilter = null; + mRasterizer = null; updateFontObject(); } @@ -1048,9 +1050,9 @@ public class Paint_Delegate { */ @SuppressWarnings("deprecation") private void updateFontObject() { - if (mTypeface != 0) { + if (mTypeface != null) { // Get the fonts from the TypeFace object. - List<Font> fonts = Typeface_Delegate.getFonts(mTypeface); + List<Font> fonts = mTypeface.getFonts(); // create new font objects as well as FontMetrics, based on the current text size // and skew info. diff --git a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java index 98a5386..c448f0e 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java @@ -65,7 +65,7 @@ public class PathDashPathEffect_Delegate extends PathEffect_Delegate { /*package*/ static int nativeCreate(int native_path, float advance, float phase, int native_style) { PathDashPathEffect_Delegate newDelegate = new PathDashPathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java index bbbebdd..4d5311a 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java @@ -61,7 +61,7 @@ public abstract class PathEffect_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int native_patheffect) { - sManager.removeDelegate(native_patheffect); + sManager.removeJavaReferenceFor(native_patheffect); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java index 9510ce0..c29e9b6 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java @@ -90,7 +90,7 @@ public final class Path_Delegate { // create the delegate Path_Delegate newDelegate = new Path_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -104,7 +104,7 @@ public final class Path_Delegate { newDelegate.set(pathDelegate); } - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -440,7 +440,7 @@ public final class Path_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int nPath) { - sManager.removeDelegate(nPath); + sManager.removeJavaReferenceFor(nPath); } diff --git a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java index bbb20e9..4ab044b 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java @@ -63,7 +63,7 @@ public class PixelXorXfermode_Delegate extends Xfermode_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(int opColor) { PixelXorXfermode_Delegate newDelegate = new PixelXorXfermode_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java index 33f6c44..c45dbaa 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java @@ -57,7 +57,7 @@ public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate { @LayoutlibDelegate /*package*/ static int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) { PorterDuffColorFilter_Delegate newDelegate = new PorterDuffColorFilter_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java index 116a773..4301c1a 100644 --- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java @@ -129,7 +129,7 @@ public class PorterDuffXfermode_Delegate extends Xfermode_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreateXfermode(int mode) { PorterDuffXfermode_Delegate newDelegate = new PorterDuffXfermode_Delegate(mode); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java index 8723ed1..9bf78b4 100644 --- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java @@ -58,7 +58,7 @@ public class RadialGradient_Delegate extends Gradient_Delegate { int colors[], float positions[], int tileMode) { RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(x, y, radius, colors, positions, Shader_Delegate.getTileMode(tileMode)); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java index 2826278..e388bd9 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java @@ -57,7 +57,7 @@ public abstract class Rasterizer_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int native_instance) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java index 7b91215..91f4347 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java @@ -266,12 +266,12 @@ public class Region_Delegate { @LayoutlibDelegate /*package*/ static int nativeConstructor() { Region_Delegate newDelegate = new Region_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate /*package*/ static void nativeDestructor(int native_region) { - sManager.removeDelegate(native_region); + sManager.removeJavaReferenceFor(native_region); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java index a1b8bdd..a008d15 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java @@ -45,7 +45,7 @@ public abstract class Shader_Delegate { // ---- delegate helper data ---- // ---- delegate data ---- - private int mLocalMatrix = 0; + private Matrix_Delegate mLocalMatrix = null; // ---- Public Helper methods ---- @@ -77,7 +77,7 @@ public abstract class Shader_Delegate { @LayoutlibDelegate /*package*/ static void nativeDestructor(int native_shader, int native_skiaShader) { - sManager.removeDelegate(native_shader); + sManager.removeJavaReferenceFor(native_shader); } @LayoutlibDelegate @@ -89,15 +89,14 @@ public abstract class Shader_Delegate { return; } - shaderDelegate.mLocalMatrix = matrix_instance; + shaderDelegate.mLocalMatrix = Matrix_Delegate.getDelegate(matrix_instance); } // ---- Private delegate/helper methods ---- protected java.awt.geom.AffineTransform getLocalMatrix() { - Matrix_Delegate localMatrixDelegate = Matrix_Delegate.getDelegate(mLocalMatrix); - if (localMatrixDelegate != null) { - return localMatrixDelegate.getAffineTransform(); + if (mLocalMatrix != null) { + return mLocalMatrix.getAffineTransform(); } return new java.awt.geom.AffineTransform(); diff --git a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java index 0c9ee48..410df0c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java @@ -64,7 +64,7 @@ public class SumPathEffect_Delegate extends PathEffect_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate(int first, int second) { SumPathEffect_Delegate newDelegate = new SumPathEffect_Delegate(); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java index 382e34c..966e06e 100644 --- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java @@ -54,7 +54,7 @@ public class SweepGradient_Delegate extends Gradient_Delegate { @LayoutlibDelegate /*package*/ static int nativeCreate1(float x, float y, int colors[], float positions[]) { SweepGradient_Delegate newDelegate = new SweepGradient_Delegate(x, y, colors, positions); - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java index 1992341..5af16ae 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java @@ -74,6 +74,10 @@ public final class Typeface_Delegate { sPostInitDelegate.clear(); } + public static Typeface_Delegate getDelegate(int nativeTypeface) { + return sManager.getDelegate(nativeTypeface); + } + public static List<Font> getFonts(Typeface typeface) { return getFonts(typeface.native_instance); } @@ -84,7 +88,11 @@ public final class Typeface_Delegate { return null; } - return delegate.mFonts; + return delegate.getFonts(); + } + + public List<Font> getFonts() { + return mFonts; } // ---- native methods ---- @@ -105,7 +113,7 @@ public final class Typeface_Delegate { sPostInitDelegate.add(newDelegate); } - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -125,7 +133,7 @@ public final class Typeface_Delegate { sPostInitDelegate.add(newDelegate); } - return sManager.addDelegate(newDelegate); + return sManager.addNewDelegate(newDelegate); } @LayoutlibDelegate @@ -144,7 +152,7 @@ public final class Typeface_Delegate { @LayoutlibDelegate /*package*/ static void nativeUnref(int native_instance) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java index 88df027..f3401fc 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java @@ -61,7 +61,7 @@ public abstract class Xfermode_Delegate { @LayoutlibDelegate /*package*/ static void finalizer(int native_instance) { - sManager.removeDelegate(native_instance); + sManager.removeJavaReferenceFor(native_instance); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java index 05a258d..295c98c 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java @@ -16,8 +16,14 @@ package com.android.layoutlib.bridge.impl; +import com.android.layoutlib.bridge.util.SparseWeakArray; + import android.util.SparseArray; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + /** * Manages native delegates. * @@ -44,13 +50,32 @@ import android.util.SparseArray; * will do is call {@link #getDelegate(int)} to get the Java object matching the int. * * Typical native init methods are returning a new int back to the Java class, so - * {@link #addDelegate(Object)} does the same. + * {@link #addNewDelegate(Object)} does the same. + * + * The JNI references are counted, so we do the same through a {@link WeakReference}. Because + * the Java object needs to count as a reference (even though it only holds an int), we use the + * following mechanism: + * + * - {@link #addNewDelegate(Object)} and {@link #removeJavaReferenceFor(int)} adds and removes + * the delegate to/from a list. This list hold the reference and prevents the GC from reclaiming + * the delegate. + * + * - {@link #addNewDelegate(Object)} also adds the delegate to a {@link SparseArray} that holds a + * {@link WeakReference} to the delegate. This allows the delegate to be deleted automatically + * when nothing references it. This means that any class that holds a delegate (except for the + * Java main class) must not use the int but the Delegate class instead. The integers must + * only be used in the API between the main Java class and the Delegate. * * @param <T> the delegate class to manage */ public final class DelegateManager<T> { - - private final SparseArray<T> mDelegates = new SparseArray<T>(); + private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>(); + /** list used to store delegates when their main object holds a reference to them. + * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed + * @see #addNewDelegate(Object) + * @see #removeJavaReferenceFor(int) + */ + private final List<T> mJavaReferences = new ArrayList<T>(); private int mDelegateCounter = 0; /** @@ -77,17 +102,20 @@ public final class DelegateManager<T> { * @param newDelegate the delegate to add * @return a unique native int to identify the delegate */ - public int addDelegate(T newDelegate) { + public int addNewDelegate(T newDelegate) { int native_object = ++mDelegateCounter; mDelegates.put(native_object, newDelegate); + assert !mJavaReferences.contains(newDelegate); + mJavaReferences.add(newDelegate); return native_object; } /** - * Removes the delegate matching the given native int. - * @param native_object the native int. + * Removes the main reference on the given delegate. + * @param native_object the native integer representing the delegate. */ - public void removeDelegate(int native_object) { - mDelegates.remove(native_object); + public void removeJavaReferenceFor(int native_object) { + T delegate = getDelegate(native_object); + mJavaReferences.remove(delegate); } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java index 3c1f627..22f1609 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java @@ -16,15 +16,33 @@ package com.android.layoutlib.bridge.util; + import com.android.internal.util.ArrayUtils; +import android.util.SparseArray; + +import java.lang.ref.WeakReference; + /** + * This is a custom {@link SparseArray} that uses {@link WeakReference} around the objects added + * to it. When the array is compacted, not only deleted indices but also empty references + * are removed, making the array efficient at removing references that were reclaimed. + * + * The code is taken from {@link SparseArray} directly and adapted to use weak references. + * + * Because our usage means that we never actually call {@link #remove(int)} or {@link #delete(int)}, + * we must manually check if there are reclaimed references to trigger an internal compact step + * (which is normally only triggered when an item is manually removed). + * * SparseArrays map integers to Objects. Unlike a normal array of Objects, * there can be gaps in the indices. It is intended to be more efficient * than using a HashMap to map Integers to Objects. */ +@SuppressWarnings("unchecked") public class SparseWeakArray<E> { - private static final Object DELETED = new Object(); + + private static final Object DELETED_REF = new Object(); + private static final WeakReference<?> DELETED = new WeakReference(DELETED_REF); private boolean mGarbage = false; /** @@ -43,7 +61,7 @@ public class SparseWeakArray<E> { initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity); mKeys = new int[initialCapacity]; - mValues = new Object[initialCapacity]; + mValues = new WeakReference[initialCapacity]; mSize = 0; } @@ -62,10 +80,10 @@ public class SparseWeakArray<E> { public E get(int key, E valueIfKeyNotFound) { int i = binarySearch(mKeys, 0, mSize, key); - if (i < 0 || mValues[i] == DELETED) { + if (i < 0 || mValues[i] == DELETED || mValues[i].get() == null) { return valueIfKeyNotFound; } else { - return (E) mValues[i]; + return (E) mValues[i].get(); } } @@ -106,12 +124,14 @@ public class SparseWeakArray<E> { int n = mSize; int o = 0; int[] keys = mKeys; - Object[] values = mValues; + WeakReference<?>[] values = mValues; for (int i = 0; i < n; i++) { - Object val = values[i]; + WeakReference<?> val = values[i]; - if (val != DELETED) { + // Don't keep any non DELETED values, but only the one that still have a valid + // reference. + if (val != DELETED && val.get() != null) { if (i != o) { keys[o] = keys[i]; values[o] = val; @@ -136,17 +156,17 @@ public class SparseWeakArray<E> { int i = binarySearch(mKeys, 0, mSize, key); if (i >= 0) { - mValues[i] = value; + mValues[i] = new WeakReference(value); } else { i = ~i; - if (i < mSize && mValues[i] == DELETED) { + if (i < mSize && (mValues[i] == DELETED || mValues[i].get() == null)) { mKeys[i] = key; - mValues[i] = value; + mValues[i] = new WeakReference(value); return; } - if (mGarbage && mSize >= mKeys.length) { + if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) { gc(); // Search again because indices may have changed. @@ -157,7 +177,7 @@ public class SparseWeakArray<E> { int n = ArrayUtils.idealIntArraySize(mSize + 1); int[] nkeys = new int[n]; - Object[] nvalues = new Object[n]; + WeakReference<?>[] nvalues = new WeakReference[n]; // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); @@ -174,7 +194,7 @@ public class SparseWeakArray<E> { } mKeys[i] = key; - mValues[i] = value; + mValues[i] = new WeakReference(value); mSize++; } } @@ -214,7 +234,7 @@ public class SparseWeakArray<E> { gc(); } - return (E) mValues[index]; + return (E) mValues[index].get(); } /** @@ -227,7 +247,7 @@ public class SparseWeakArray<E> { gc(); } - mValues[index] = value; + mValues[index] = new WeakReference(value); } /** @@ -257,7 +277,7 @@ public class SparseWeakArray<E> { } for (int i = 0; i < mSize; i++) - if (mValues[i] == value) + if (mValues[i].get() == value) return i; return -1; @@ -268,7 +288,7 @@ public class SparseWeakArray<E> { */ public void clear() { int n = mSize; - Object[] values = mValues; + WeakReference<?>[] values = mValues; for (int i = 0; i < n; i++) { values[i] = null; @@ -288,7 +308,7 @@ public class SparseWeakArray<E> { return; } - if (mGarbage && mSize >= mKeys.length) { + if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) { gc(); } @@ -297,7 +317,7 @@ public class SparseWeakArray<E> { int n = ArrayUtils.idealIntArraySize(pos + 1); int[] nkeys = new int[n]; - Object[] nvalues = new Object[n]; + WeakReference<?>[] nvalues = new WeakReference[n]; // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); @@ -308,10 +328,20 @@ public class SparseWeakArray<E> { } mKeys[pos] = key; - mValues[pos] = value; + mValues[pos] = new WeakReference(value); mSize = pos + 1; } + private boolean hasReclaimedRefs() { + for (int i = 0 ; i < mSize ; i++) { + if (mValues[i].get() == null) { // DELETED.get() never returns null. + return true; + } + } + + return false; + } + private static int binarySearch(int[] a, int start, int len, int key) { int high = start + len, low = start - 1, guess; @@ -333,6 +363,6 @@ public class SparseWeakArray<E> { } private int[] mKeys; - private Object[] mValues; + private WeakReference<?>[] mValues; private int mSize; } |