mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 10:20:25 +01:00
Drastically reduce number of projection instances we create.
Via SimplePool
This commit is contained in:
@@ -9,6 +9,7 @@ import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.util.Pools;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
@@ -24,30 +25,41 @@ import java.util.Objects;
|
||||
*/
|
||||
public final class Projection {
|
||||
|
||||
private final float x;
|
||||
private final float y;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final Corners corners;
|
||||
private final Path path;
|
||||
private final RectF rect;
|
||||
private float x;
|
||||
private float y;
|
||||
private int width;
|
||||
private int height;
|
||||
private Corners corners;
|
||||
private Path path;
|
||||
private RectF rect;
|
||||
|
||||
public Projection(float x, float y, int width, int height, @Nullable Corners corners) {
|
||||
private Projection() {
|
||||
x = 0f;
|
||||
y = 0f;
|
||||
width = 0;
|
||||
height = 0;
|
||||
corners = null;
|
||||
path = new Path();
|
||||
rect = new RectF();
|
||||
}
|
||||
|
||||
private Projection set(float x, float y, int width, int height, @Nullable Corners corners) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.corners = corners;
|
||||
this.path = new Path();
|
||||
|
||||
rect = new RectF();
|
||||
rect.set(x, y, x + width, y + height);
|
||||
path.reset();
|
||||
|
||||
if (corners != null) {
|
||||
path.addRoundRect(rect, corners.toRadii(), Path.Direction.CW);
|
||||
} else {
|
||||
path.addRect(rect, Path.Direction.CW);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
@@ -86,35 +98,12 @@ public final class Projection {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final Projection that = (Projection) o;
|
||||
return Float.compare(that.x, x) == 0 &&
|
||||
Float.compare(that.y, y) == 0 &&
|
||||
width == that.width &&
|
||||
height == that.height &&
|
||||
Objects.equals(corners, that.corners);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return Objects.hash(x, y, width, height, corners);
|
||||
}
|
||||
|
||||
public @NonNull Projection translateX(float xTranslation) {
|
||||
return new Projection(x + xTranslation, y, width, height, corners);
|
||||
return set(x + xTranslation, y, width, height, corners);
|
||||
}
|
||||
|
||||
public @NonNull Projection translateY(float yTranslation) {
|
||||
return new Projection(x, y + yTranslation, width, height, corners);
|
||||
}
|
||||
|
||||
public @NonNull Projection withDimensions(int width, int height) {
|
||||
return new Projection(x, y, width, height, corners);
|
||||
}
|
||||
|
||||
public @NonNull Projection withHeight(int height) {
|
||||
return new Projection(x, y, width, height, corners);
|
||||
return set(x, y + yTranslation, width, height, corners);
|
||||
}
|
||||
|
||||
public static @NonNull Projection relativeToParent(@NonNull ViewGroup parent, @NonNull View view, @Nullable Corners corners) {
|
||||
@@ -122,7 +111,7 @@ public final class Projection {
|
||||
|
||||
view.getDrawingRect(viewBounds);
|
||||
parent.offsetDescendantRectToMyCoords(view, viewBounds);
|
||||
return new Projection(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
|
||||
return acquireAndSet(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
|
||||
}
|
||||
|
||||
public static @NonNull Projection relativeToViewRoot(@NonNull View view, @Nullable Corners corners) {
|
||||
@@ -132,7 +121,7 @@ public final class Projection {
|
||||
view.getDrawingRect(viewBounds);
|
||||
root.offsetDescendantRectToMyCoords(view, viewBounds);
|
||||
|
||||
return new Projection(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
|
||||
return acquireAndSet(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
|
||||
}
|
||||
|
||||
public static @NonNull Projection relativeToViewWithCommonRoot(@NonNull View toProject, @NonNull View viewWithCommonRoot, @Nullable Corners corners) {
|
||||
@@ -143,7 +132,7 @@ public final class Projection {
|
||||
root.offsetDescendantRectToMyCoords(toProject, viewBounds);
|
||||
root.offsetRectIntoDescendantCoords(viewWithCommonRoot, viewBounds);
|
||||
|
||||
return new Projection(viewBounds.left, viewBounds.top, toProject.getWidth(), toProject.getHeight(), corners);
|
||||
return acquireAndSet(viewBounds.left, viewBounds.top, toProject.getWidth(), toProject.getHeight(), corners);
|
||||
}
|
||||
|
||||
public static @NonNull Projection translateFromDescendantToParentCoords(@NonNull Projection descendantProjection, @NonNull View descendant, @NonNull ViewGroup parent) {
|
||||
@@ -153,7 +142,7 @@ public final class Projection {
|
||||
|
||||
parent.offsetDescendantRectToMyCoords(descendant, viewBounds);
|
||||
|
||||
return new Projection(viewBounds.left, viewBounds.top, descendantProjection.width, descendantProjection.height, descendantProjection.corners);
|
||||
return acquireAndSet(viewBounds.left, viewBounds.top, descendantProjection.width, descendantProjection.height, descendantProjection.corners);
|
||||
}
|
||||
|
||||
public static @NonNull List<Projection> getCapAndTail(@NonNull Projection parentProjection, @NonNull Projection childProjection) {
|
||||
@@ -187,11 +176,47 @@ public final class Projection {
|
||||
}
|
||||
|
||||
return Arrays.asList(
|
||||
new Projection(topX, topY, topWidth, topHeight, topCorners),
|
||||
new Projection(bottomX, bottomY, bottomWidth, bottomHeight, bottomCorners)
|
||||
acquireAndSet(topX, topY, topWidth, topHeight, topCorners),
|
||||
acquireAndSet(bottomX, bottomY, bottomWidth, bottomHeight, bottomCorners)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* We keep a maximum of 125 Projections around at any one time.
|
||||
*/
|
||||
private static final Pools.SimplePool<Projection> projectionPool = new Pools.SimplePool<>(125);
|
||||
|
||||
/**
|
||||
* Acquire a projection. This will try to grab one from the pool, and, upon failure, will
|
||||
* allocate a new one instead.
|
||||
*/
|
||||
private static @NonNull Projection acquire() {
|
||||
Projection fromPool = projectionPool.acquire();
|
||||
if (fromPool != null) {
|
||||
return fromPool;
|
||||
} else {
|
||||
return new Projection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire a projection and set its fields as specified.
|
||||
*/
|
||||
private static @NonNull Projection acquireAndSet(float x, float y, int width, int height, @Nullable Corners corners) {
|
||||
Projection projection = acquire();
|
||||
projection.set(x, y, width, height, corners);
|
||||
|
||||
return projection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Projections should only be kept around for the absolute maximum amount of time they are needed.
|
||||
*/
|
||||
public void release() {
|
||||
projectionPool.release(this);
|
||||
}
|
||||
|
||||
|
||||
public static final class Corners {
|
||||
private final float topLeft;
|
||||
private final float topRight;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.thoughtcrime.securesms.util
|
||||
|
||||
import java.io.Closeable
|
||||
|
||||
class ProjectionList(size: Int = 0) : ArrayList<Projection>(size), Closeable {
|
||||
override fun close() {
|
||||
forEach { it.release() }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user