Fix performance issues caused by 8d15a25dcbb23
The earlier commit would maintain a static list of styles, and every time
a style resource was added to a theme, it would stay there until the end
of time (or termination of JVM). When executing thousands of tests, this
would lead to massive slowdown of test execution - over 2x increase in
our company's case.
Now, the duplicate styles are removed and the new one is added, which keeps
the list short and performance reasonable.
Change-Id: Ib7ed9321c31938577c78aab52a1d8380bf1be4e6
diff --git a/robolectric-resources/src/main/java/org/robolectric/res/StyleData.java b/robolectric-resources/src/main/java/org/robolectric/res/StyleData.java
index 73cb1a6..6bf03ec 100644
--- a/robolectric-resources/src/main/java/org/robolectric/res/StyleData.java
+++ b/robolectric-resources/src/main/java/org/robolectric/res/StyleData.java
@@ -1,5 +1,7 @@
package org.robolectric.res;
+import org.robolectric.util.Strings;
+
import java.util.LinkedHashMap;
import java.util.Map;
@@ -42,6 +44,29 @@
return attribute;
}
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof StyleData)) {
+ return false;
+ }
+ StyleData other = (StyleData) obj;
+
+ return Strings.equals(packageName, other.packageName)
+ && Strings.equals(name, other.name)
+ && Strings.equals(parent, other.parent)
+ && items.size() == other.items.size();
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 0;
+ hashCode = 31 * hashCode + Strings.nullToEmpty(packageName).hashCode();
+ hashCode = 31 * hashCode + Strings.nullToEmpty(name).hashCode();
+ hashCode = 31 * hashCode + Strings.nullToEmpty(parent).hashCode();
+ hashCode = 31 * hashCode + items.size();
+ return hashCode;
+ }
+
@Override public String toString() {
return "StyleData{" +
"name='" + name + '\'' +
diff --git a/robolectric-shadows/shadows-core/src/main/resources/org/robolectric/shadows/ShadowAssetManager.java.vm b/robolectric-shadows/shadows-core/src/main/resources/org/robolectric/shadows/ShadowAssetManager.java.vm
index 5e00180..52de4d3 100644
--- a/robolectric-shadows/shadows-core/src/main/resources/org/robolectric/shadows/ShadowAssetManager.java.vm
+++ b/robolectric-shadows/shadows-core/src/main/resources/org/robolectric/shadows/ShadowAssetManager.java.vm
@@ -43,6 +43,7 @@
import org.robolectric.res.StyleData;
import org.robolectric.res.TypedResource;
import org.robolectric.res.builder.XmlFileBuilder;
+import org.robolectric.util.Strings;
import static org.robolectric.Shadows.shadowOf;
import static org.robolectric.shadows.ShadowApplication.getInstance;
@@ -274,7 +275,15 @@
Style style = resolveStyle(resourceLoader, null, resName, assetManager.getQualifiers());
- APPLIED_STYLES.get(theme).add(new OverlayedStyle(style, force));
+ List<OverlayedStyle> overlayedStyleList = APPLIED_STYLES.get(theme);
+ OverlayedStyle styleToAdd = new OverlayedStyle(style, force);
+ for (int i = 0; i < overlayedStyleList.size(); ++i) {
+ if (styleToAdd.equals(overlayedStyleList.get(i))) {
+ overlayedStyleList.remove(i);
+ break;
+ }
+ }
+ overlayedStyleList.add(styleToAdd);
}
static List<OverlayedStyle> getOverlayThemeStyles($ptrClass themeResourceId) {
@@ -289,6 +298,20 @@
this.style = style;
this.force = force;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof OverlayedStyle)) {
+ return false;
+ }
+ OverlayedStyle overlayedStyle = (OverlayedStyle) obj;
+ return style.equals(overlayedStyle.style);
+ }
+
+ @Override
+ public int hashCode() {
+ return style.hashCode();
+ }
}
@HiddenApi @Implementation
@@ -510,6 +533,29 @@
throw new RuntimeException("Found a " + attr + " but can't cast it :(");
}
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof StyleResolver)) {
+ return false;
+ }
+ StyleResolver other = (StyleResolver) obj;
+
+ return ((theme == null && other.theme == null) || (theme != null && theme.equals(other.theme)))
+ && ((myResName == null && other.myResName == null)
+ || (myResName != null && myResName.equals(other.myResName)))
+ && Strings.equals(qualifiers, other.qualifiers);
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 0;
+ hashCode = 31 * hashCode + (theme != null ? theme.hashCode() : 0);
+ hashCode = 31 * hashCode + (myResName != null ? myResName.hashCode() : 0);
+ hashCode = 31 * hashCode + Strings.nullToEmpty(qualifiers).hashCode();
+ return hashCode;
+ }
+
+ @Override
public String toString() {
return "StyleResolver{"
+ "name=" + myResName
diff --git a/robolectric-utils/src/main/java/org/robolectric/util/Strings.java b/robolectric-utils/src/main/java/org/robolectric/util/Strings.java
index 9b61904..b9875d5 100644
--- a/robolectric-utils/src/main/java/org/robolectric/util/Strings.java
+++ b/robolectric-utils/src/main/java/org/robolectric/util/Strings.java
@@ -22,4 +22,8 @@
}
return a.equals(b);
}
+
+ public static String nullToEmpty(String string) {
+ return string == null ? "" : string;
+ }
}