Don't trigger TextView relayouts if content doesn't change

We have a few views we commonly update in response to updates - clock, battery and similar percentages. These updates always trigger a requestLayout() call because wrap_content TextViews do that on every setText() call. This CL adds a few guards to lower the amount of relayouts when the content didn't actually update.

Bug:228203088
Bug:228166250

Test: On a physical deviceo
Change-Id: I6b92f8bfb7aea17e93ff0cbb8507a995f6323ca1
This commit is contained in:
Jernej Virag
2022-04-05 19:26:15 +00:00
parent 5e230aef5e
commit 2d38106f6e
3 changed files with 42 additions and 9 deletions

View File

@@ -22,6 +22,7 @@ import android.annotation.IntRange
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.text.TextUtils
import android.text.format.DateFormat
import android.util.AttributeSet
import android.util.Log
@@ -125,13 +126,30 @@ class AnimatableClockView @JvmOverloads constructor(
fun refreshTime() {
time.timeInMillis = System.currentTimeMillis()
text = DateFormat.format(format, time)
contentDescription = DateFormat.format(descFormat, time)
Log.d(tag, "refreshTime this=$this" +
" currTimeContextDesc=$contentDescription" +
" measuredHeight=$measuredHeight" +
" lastMeasureCall=$lastMeasureCall" +
" isSingleLineInternal=$isSingleLineInternal")
val formattedText = DateFormat.format(format, time)
// Setting text actually triggers a layout pass (because the text view is set to
// wrap_content width and TextView always relayouts for this). Avoid needless
// relayout if the text didn't actually change.
if (!TextUtils.equals(text, formattedText)) {
text = formattedText
Log.d(
tag, "refreshTime this=$this" +
" currTimeContextDesc=$contentDescription" +
" measuredHeight=$measuredHeight" +
" lastMeasureCall=$lastMeasureCall" +
" isSingleLineInternal=$isSingleLineInternal"
)
} else {
Log.d(
tag, "refreshTime (skipped due to unchanged text)" +
" this=$this" +
" currTimeContextDesc=$contentDescription" +
" measuredHeight=$measuredHeight" +
" lastMeasureCall=$lastMeasureCall" +
" isSingleLineInternal=$isSingleLineInternal"
)
}
}
fun onTimeZoneChanged(timeZone: TimeZone?) {

View File

@@ -32,6 +32,7 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
@@ -267,8 +268,15 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver {
if (mBatteryPercentView == null) {
return;
}
mBatteryPercentView.setText(
NumberFormat.getPercentInstance().format(mLevel / 100f));
String percentText = NumberFormat.getPercentInstance().format(mLevel / 100f);
// Setting text actually triggers a layout pass (because the text view is set to
// wrap_content width and TextView always relayouts for this). Avoid needless
// relayout if the text didn't actually change.
if (!TextUtils.equals(mBatteryPercentView.getText(), percentText)) {
mBatteryPercentView.setText(percentText);
}
setContentDescription(
getContext().getString(mCharging ? R.string.accessibility_battery_level_charging
: R.string.accessibility_battery_level, mLevel));

View File

@@ -31,6 +31,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.text.style.CharacterStyle;
import android.text.style.RelativeSizeSpan;
@@ -291,7 +292,13 @@ public class Clock extends TextView implements
final void updateClock() {
if (mDemoMode) return;
mCalendar.setTimeInMillis(System.currentTimeMillis());
setText(getSmallTime());
CharSequence smallTime = getSmallTime();
// Setting text actually triggers a layout pass (because the text view is set to
// wrap_content width and TextView always relayouts for this). Avoid needless
// relayout if the text didn't actually change.
if (!TextUtils.equals(smallTime, getText())) {
setText(smallTime);
}
setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime()));
}