tom91136
tom91136

Reputation: 8962

Android View.post() method making excessive reference

Sorry I can't come up with a better question title because it's pretty hard to describe...

I was inspecting Android's source (4.4 KK), the View class in particular and this showed up:

// .... lots of stuff....
AttachInfo mAttachInfo;
// .... lots of stuff....
public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().post(action);
    return true;
}

That's the View.post(Runnable) that we all love to use whenever we need something to run on the UI thread.

The thing I don't understand here is why do they create another local reference of attachInfo?

Why don't they do it like:

    if (mAttachInfo != null) {
        return mAttachInfo.mHandler.post(action);
    }

Other than making attachInfo immutable in the method scope to prevent bugs(even thought they can still accidentally access mAttachInfo), I don't think there's any reason to do this.

Another possibility would be to shorten names, but I don't think it's worth shorting 1 character.

Is this a design pattern?

EDIT: further inspecting the source reveals that they use this "pattern" in many places:

public void postInvalidateOnAnimation() {
    // We try only with the AttachInfo because there's no point in invalidating
    // if we are not attached to our window
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this);
    }
}

Basically, they use it in almost every postXXXXXX() method.

EDIT2:

@CommonsWare pointed out that it might be used for anonymous inner class in previous versions, I checked the source of 1.5(Cupcake) ~ 2.3.3(Gingerbread) and this is what post() looks like

public boolean post(Runnable action) {
    Handler handler;
    if (mAttachInfo != null) {
        handler = mAttachInfo.mHandler;
    } else {
        // Assume that post will succeed later
        ViewRoot.getRunQueue().post(action);
        return true;
    }

    return handler.post(action);
}

I still don't see why....

Upvotes: 0

Views: 1254

Answers (1)

akwizgran
akwizgran

Reputation: 176

Bear in mind that post() may be called from background threads at the same time as mAttachInfo is updated on the UI thread. The code that was used up to Android 2.3.3 could throw an NPE if mAttachInfo was set to null after the if (mAttachInfo != null) check and before mAttachInfo.mHandler was accessed.

The current code avoids the NPE by taking a snapshot of mAttachInfo that doesn't change for the lifetime of the method.

The local variable doesn't strictly need to be final, but declaring it final makes it extra clear that it won't become null after the if (attachInfo != null) check.

Upvotes: 1

Related Questions