From 057dad3a09c6b041d6ce3ca38a76bca2f6254fb3 Mon Sep 17 00:00:00 2001 From: Joshua Quick Date: Thu, 3 Oct 2019 13:22:30 -0700 Subject: [PATCH] fix(android): performance issue with deeply nested views as of 7.5.0 (#11253) --- .../titanium/view/TiCompositeLayout.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/android/titanium/src/java/org/appcelerator/titanium/view/TiCompositeLayout.java b/android/titanium/src/java/org/appcelerator/titanium/view/TiCompositeLayout.java index 906655502be..91758811104 100644 --- a/android/titanium/src/java/org/appcelerator/titanium/view/TiCompositeLayout.java +++ b/android/titanium/src/java/org/appcelerator/titanium/view/TiCompositeLayout.java @@ -21,6 +21,7 @@ import android.app.Activity; import android.content.Context; +import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; @@ -94,6 +95,13 @@ public enum LayoutArrangement { */ private int childFillHeight = -1; + /** + * The last window insets object received by the onApplyWindowInsets() method. + * This object is immutable. Will be null if not received yet or has been cleared. + * Note: This references an Android 5.0 class. Do NOT access it in older Android OS versions. + */ + private WindowInsets previousInsets; + private WeakReference proxy; // We need these two constructors for backwards compatibility with modules @@ -464,6 +472,13 @@ public WindowInsets onApplyWindowInsets(WindowInsets insets) return null; } + // Do not propagate given insets to child views unless the insets have changed. + // This greatly improves performance if we have deeply nested views since each view will trigger a relayout. + if (insets.equals(this.previousInsets)) { + return insets; + } + this.previousInsets = insets; + // Apply insets to all child views and don't let them consume given insets. // We must do this since a "composite" layout supports overlapping views. final int childCount = getChildCount(); @@ -476,6 +491,49 @@ public WindowInsets onApplyWindowInsets(WindowInsets insets) return insets; } + /** + * Requests parent view (and the parent's parent) to redispatch system insets to all child views. + * This method should be called when dynamically adding views that have setFitsSystemWindows() set to true. + */ + @Override + public void requestApplyInsets() + { + // The super class' method is only supported on Android 5.0 and higher. + if (Build.VERSION.SDK_INT < 20) { + return; + } + + // Clear last stored insets and then request parent to redispatch system insets to all child views. + this.previousInsets = null; + super.requestApplyInsets(); + } + + /** + * Requests parent view (and the parent's parent) to redispatch system insets to all child views. + * This method should be called when dynamically adding views that have setFitsSystemWindows() set to true. + */ + @Override + public void requestFitSystemWindows() + { + // Clear last stored insets and then request parent to redispatch system insets to all child views. + if (Build.VERSION.SDK_INT >= 20) { + this.previousInsets = null; + } + super.requestFitSystemWindows(); + } + + /** Called when this view has been detached/removed from the activity window. */ + @Override + protected void onDetachedFromWindow() + { + super.onDetachedFromWindow(); + + // Clear last stored insets received by the onApplyWindowInsets() method. + if (Build.VERSION.SDK_INT >= 20) { + this.previousInsets = null; + } + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {