android app无限运行onPreDraw

时间:2017-07-28 10:37:13

标签: android

步骤1.使用导航抽屉模板创建一个新应用程序。

create a new app with Navigation Drawer template

步骤2.添加自定义按钮并覆盖onMeasure方法。

@CoordinatorLayout.DefaultBehavior(MyButton.Behavior.class)
public class MyButton extends android.support.v7.widget.AppCompatButton {

private ViewTreeObserver.OnPreDrawListener mPreDrawListener;

public MyButton(Context context) {
    super(context);
}

public MyButton(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    if (mPreDrawListener == null) {
        mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                offsetTopAndBottom(50);
                return true;
            }
        };

        ViewParent p = getParent();
        if (p instanceof View) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                ((View)p).getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
            }
        }
    }
}

public static class Behavior extends CoordinatorLayout.Behavior<MyButton> {

    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, MyButton child, int layoutDirection) {
        final List<View> dependencies = parent.getDependencies(child);
        return super.onLayoutChild(parent, child, layoutDirection);
    }

    @Override
    public void onAttachedToLayoutParams(@NonNull CoordinatorLayout.LayoutParams lp) {
        if (lp.dodgeInsetEdges == Gravity.NO_GRAVITY) {
            // If the developer hasn't set dodgeInsetEdges, lets set it to BOTTOM so that
            // we dodge any Snackbars
            lp.dodgeInsetEdges = Gravity.BOTTOM;
        }
    }
}

}

第3步。在app_bar_main布局中使用MyButton

enter image description here

步骤4.在onPreDraw中设置断点然后我可以看到它将无限执行。如果我评论offsetTopAndBottom(50),一切都会顺利。

enter image description here

我还会一遍又一遍地跟踪源代码并查找应用程序接收vsync信号,这会导致Choreographer.java中的onVsync函数无限运行。为什么会这样?

更新

如果我设置如下的断点并注释onPreDraw,则最终将无法达到此断点,否则,它总是可以到达。

enter image description here

1 个答案:

答案 0 :(得分:1)

在绘制每个帧之前调用回调<ul class"list"> <li>first list item</li> <li>second list item</li> <div> <li>third list item</li> <li>fourth list item</li> </div> <li>fifth list item</li> <li>sixth list item</li> </ul> <form> <select> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> <option value="6">6</option> </select> </select> <button type="button">Select List Item</button> </form>。由于你通常会继续绘制画框(~60fps),因此被称为“#34;无限地”#34;这是正常的。

为了避免这种行为,通常的模式是将监听器作为onPreDraw()中的第一个语句删除:

onPreDraw()

其中view.getViewTreeObserver().removeOnPreDrawListener(this); 是您案例中的降级父母。

您可以在this video中看到示例代码。工程师是Android Framework团队的一员。