关于android:View.setVisibility(View.VISIBLE)是否强制视图重新绘制,即使该视图已经可见?

Does View.setVisibility(View.VISIBLE) forces the view to redraw even if it's already visible?

我试图找出针对我的自定义视图的优化。 我想知道是否对View.setVisibility(View.VISIBLE)的调用会强制Android框架更新视图可见性(<-强制重新绘制视图),即使视图已经可见。


不,不是。

看一下setVisibility()

1
2
3
4
public void setVisibility(int visibility) {
    setFlags(visibility, VISIBILITY_MASK);
    if (mBGDrawable != null) mBGDrawable.setVisible(visibility == VISIBLE, false);
}

它只是调用setFlags(),如果没有任何变化,它将立即返回:

1
2
3
4
5
....
int changed = mViewFlags ^ old;
if (changed == 0) {
    return;
}

即使(以某种方式)到达那里,它也会检查各个标志的变化,并且仅在其中一个标志与实际标志不同时才进行更新。


View#setVisibility中查看:

1
2
3
4
public void setVisibility(int visibility) {
    setFlags(visibility, VISIBILITY_MASK);
    if (mBackground != null) mBackground.setVisible(visibility == VISIBLE, false);
}

setFlags(...)方法开始于:

1
2
3
4
5
6
7
int old = mViewFlags;
mViewFlags = (mViewFlags & ~mask) | (flags & mask);

int changed = mViewFlags ^ old;
if (changed == 0) {
    return;
}

因此,我很确定此方法不会执行任何操作。否则,除了触发布局和重绘之外,它还会做很多事情。

Background#setVisible类似于:

1
2
3
4
5
6
7
8
public boolean setVisible(boolean visible, boolean restart) {
    boolean changed = mVisible != visible;
    if (changed) {
        mVisible = visible;
        invalidateSelf();
    }
    return changed;
}

if将为false,因此不会执行任何操作。

但是,View#setVisible()被以下内容覆盖:ImageViewMediaRouteButtonProgressBarSurfaceViewViewStub。您需要检查每个实现是否还有其他额外的功能-您可能正在使用这些子类之一。

Drawable同样适用:有8个类覆盖Drawable#setVisible(boolean, boolean)

  • 剪贴画
  • DrawableContainer
  • AnimationDrawable-从DrawableContainer扩展
  • InsetDrawable
  • LayerDrawable
  • RotateDrawble
  • 可缩放比例
  • SlideDrawable
  • 根据您的组合,您可能会发现您实际上正在做一些额外的事情,因此您需要调查使用的是哪种View及其背景可绘制对象。


    我不是100%,但我不这么认为

    从View类的grepcode中获得,这是从setFlags(int flags, int mask)方法获得的,该方法从setVisibility(int visibility)中调用

    1
    2
    3
    4
    int changed = mViewFlags ^ old;
    if (changed == 0) {
        return;
    }

    之后,以相同的方法调用requestLayout()invalidate()

    所以我说不,那不是


    setVisibility()通过在内部调用setFlags来设置视图标志。如果进入sdk View.setFlags(),我们可以看到,如果标志状态不变,则此方法无关。 sdk View.setFlags()方法中的代码:int changed = mViewFlags ^ old;
    if (changed == 0) {
    return;
    }