Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e37d629 authored by Gilles Debunne's avatar Gilles Debunne
Browse files

Remove onPreDrawListeners earlier in TextView

Bug 5556478

Launcher pre-populates its all apps and widget pages with their
content, which includes text. The layout calls some onMeasure methods
that trigger TextView's registerForPreDraw(), which in turns adds a
listener in the ViewTreeObserver.

However, some of these pages may never be actually displayed, leaving
the listeners in the list since onDraw() is never called.

As a result, every frame displayed by launcher is slowned down by this
array copy of 6-18 listeners.

The problem is not Launcher specific since other applications may use
a similar caching mechanism.

The solution is to unsubscribe the listener in onPreDraw.

The drawback is that several successive calls to registerForPreDraw() will
add/remove the some listener object. However, these calls are rare and are
relatively cheap since we're just adding the object in and out of an
ArrayList which should not need to change its size.

Change-Id: Ifb65655a27e302d31a2ad622d18f839aec99689e
parent 566e8baf
Loading
Loading
Loading
Loading
+10 −28
Original line number Diff line number Diff line
@@ -256,10 +256,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener

    private float mShadowRadius, mShadowDx, mShadowDy;

    private static final int PREDRAW_NOT_REGISTERED = 0;
    private static final int PREDRAW_PENDING = 1;
    private static final int PREDRAW_DONE = 2;
    private int mPreDrawState = PREDRAW_NOT_REGISTERED;
    private boolean mPreDrawRegistered;

    private TextUtils.TruncateAt mEllipsize = null;

@@ -4387,26 +4384,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }

    private void registerForPreDraw() {
        final ViewTreeObserver observer = getViewTreeObserver();

        if (mPreDrawState == PREDRAW_NOT_REGISTERED) {
            observer.addOnPreDrawListener(this);
            mPreDrawState = PREDRAW_PENDING;
        } else if (mPreDrawState == PREDRAW_DONE) {
            mPreDrawState = PREDRAW_PENDING;
        if (!mPreDrawRegistered) {
            getViewTreeObserver().addOnPreDrawListener(this);
            mPreDrawRegistered = true;
        }

        // else state is PREDRAW_PENDING, so keep waiting.
    }

    /**
     * {@inheritDoc}
     */
    public boolean onPreDraw() {
        if (mPreDrawState != PREDRAW_PENDING) {
            return true;
        }

        if (mLayout == null) {
            assumeLayout();
        }
@@ -4457,7 +4444,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            startSelectionActionMode();
        }

        mPreDrawState = PREDRAW_DONE;
        getViewTreeObserver().removeOnPreDrawListener(this);
        mPreDrawRegistered = false;

        return !changed;
    }

@@ -4492,10 +4481,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        final ViewTreeObserver observer = getViewTreeObserver();
        if (mPreDrawState != PREDRAW_NOT_REGISTERED) {
            observer.removeOnPreDrawListener(this);
            mPreDrawState = PREDRAW_NOT_REGISTERED;
        if (mPreDrawRegistered) {
            getViewTreeObserver().removeOnPreDrawListener(this);
            mPreDrawRegistered = false;
        }

        if (mError != null) {
@@ -4768,12 +4756,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener

    @Override
    protected void onDraw(Canvas canvas) {
        if (mPreDrawState == PREDRAW_DONE) {
            final ViewTreeObserver observer = getViewTreeObserver();
            observer.removeOnPreDrawListener(this);
            mPreDrawState = PREDRAW_NOT_REGISTERED;
        }

        if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return;

        restartMarqueeIfNeeded();