Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > Android ViewRootImpl

Android那两个你碰不到但是很重要的类之ViewRootImpl

作者:Drummor

这两个类就是ActivityThread和ViewRootImpl,之所以说碰不到是因为我们无法通过正常的方式引用这两个类或者其类的对象,本文就尝试从几个我们经常接触的方面先谈谈ViewRootImpl,感兴趣的可以参考阅读下

前言

这两个类就是ActivityThread和ViewRootImpl,之所以说碰不到是因为我们无法通过正常的方式引用这两个类或者其类的对象,调用方法或者直接拿他的属性。但他们其实又无处不在,应用开发中很多时候都和他们息息相关,阅读他们掌握其内部实现对我们理解Android运行机理有醍醐灌顶之疗效,码读百变其义自见,常读常新。本文就尝试从几个我们经常接触的方面先谈谈ViewRootImpl。

1.ViewRootImpl哪来的?

首先是ViewRootImpl,位于android.view包下,从它所处的位置大概能猜到,跟View相关。其作用一句话总结,就是连接Window和View的纽带。

这个要从我们最熟悉的Activity开始,我们知道Activity的设置布局View是通过setContentView() 方法这个方法里面也大有文章,我们简单的梳理下。

public void handleResumeActivity(){
    r.window = r.activity.getWindow();
    View decor = r.window.getDecorView();
    ViewManager wm = a.getWindowManager();
    ViewManager wm = a.getWindowManager();
    WindowManager.LayoutParams l = r.window.getAttributes();
    wm.addView(decor, l);
}
public void addView(){
    root = new ViewRootImpl(view.getContext(), display);
    view.setLayoutParams(wparams);
    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);
}

小结

2 ViewRootImpl 一个View链渲染的中转站

View的渲染是自定而上层层向下发起的,大致经历测量布局和绘制,View链的管理者就是ViewRootImpl。通过

scheduleTraversals()方法发起渲染动作。交给Choreographer安排真正执行的时间关于Choreographer不熟悉的可以参考我的其他文章。最终执行performTraversals() 方法。

private void performTraversals(){
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    performLayout(lp, mWidth, mHeight);
    performDraw();
}

3 不能在子线程操作View?

ViewRoot的RequestLayout中有这样一段代码:

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
}

4 View 挂载

private void performTraversals(){
    host.dispatchAttachedToWindow(mAttachInfo, 0);//此处的host为ViewGroup
}
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
    for (int i = 0; i < count; i++) {
        final View child = children[i];
        child.dispatchAttachedToWindow(info,
                combineVisibility(visibility, child.getVisibility()));
    }
 

通过addView添加进的View也是会收到父View的mAttachInfo这里不展开了。

5 View.post()的Runnable最终在哪执行了?

public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }
    getRunQueue().post(action);
    return true;
}
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
  ..
    if (mRunQueue != null) {
        mRunQueue.executeActions(info.mHandler);//内部也是调用handler.post()
        mRunQueue = null;
    }
    ..
}

6 为什么View.post 可以获取宽高

7 还有一点值得注意

ViewRootImpl 不单单是渲染的中转站,还是触摸事件的中转站。

硬件传感器接收到触摸事件经过层层传递分发到应用窗口的第一站就是ViewRootImpl。为什么这么说?因为我有证据~。这是ViewRoot里的代码

public void setView(){
    ..
    mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
        Looper.myLooper());
}

总结

以上就是Android那两个你碰不到但是很重要的类之ViewRootImpl的详细内容,更多关于Android ViewRootImpl的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文