android ui 简介

来源:互联网 发布:sas数据分析大赛客观题 编辑:程序博客网 时间:2024/06/05 05:54

在介绍Framework相关模块的内容时,相比于把详细的流程代码贴出来,我更愿意把模块的层次结构、各个组件的关联以图形的形式呈现出来。所以按照国际惯例,直接上图,下面就开始介绍ViewrootImpl,SurfaceView(GlSurfaceView 本身继承自SurfaceView,没有太多可介绍的,所以没有画出来),TextureView。


1、ViewRootImpl

  这个类是view的管理者,真正的根节点是mView(DecorView实例),这里将ViewRootImpl画出来,更能清楚显示出ui的结构和相关模块。如图中的WindowInputEventReceiver,就是负责接收InputManager上报上来的input事件。Surface是BufferQueue的producer端,渲染后的buffer通过它送到surfaceflinger去显示。IwindowSession和IWindow.Stub是和WindowManagerService打交道,一个充当binder的proxy端,另一个充当server端,这样就可以实现双向通信。除了和WindowManagerService有联系,还和很多其他模块相关联,这里就不一一画出来了,

1)input 事件上报

在InputManagerService中有两个线程,InputReaderThread负责从EventHub读取Event,经过处理后,交给InputDispatcherThread上报给上层,忽略其他Service对特殊事件的处理,可以简单的认为InputDispatcherThread将input事件给到了Activity(应用)。

InputReader从input driver读到input evnet后,会经过多个模块的处理,其中InputMapper的处理最为负责,有兴趣可以看一下源码,然后丢给QueuedInputListener去notify。

void QueuedInputListener::flush() {    size_t count = mArgsQueue.size();    for (size_t i = 0; i < count; i++) {        NotifyArgs* args = mArgsQueue[i];        args->notify(mInnerListener);        delete args;    }    mArgsQueue.clear();}

有些同学可能不理解mInnerListener 是什么,这个其实是InputDispatcher实例,所以InputReader读到的事件,经过各种处理和包装,到这里就丢到InputDispatcher的队列里面去了,接下来就由InputDispatcher (InputDispatcherThread线程)将事件给到应用。这里是一个跨进程的数据传输,这里用到的是socket方式,InputChannel就是对socket两端读写操作的封装。

status_t InputChannel::sendMessage(const InputMessage* msg) {    size_t msgLength = msg->size();    ssize_t nWrite;    do {        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);    } while (nWrite == -1 && errno == EINTR);    ...    return OK;}status_t InputChannel::receiveMessage(InputMessage* msg) {    ssize_t nRead;    do {        nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);    } while (nRead == -1 && errno == EINTR);    ...    return OK;}

封装得再好,最终还是得调用send(…)和recv(…)接口来发送和接收数据,这种方式和应用从sensorservice读数据方式是一样的,都是用到了socket,具体说来是socketpair。

ViewRootImpl的WindowInputEventReceiver收到input事件后,可能经常一系列的处理后,传给DecorView,例如touch事件

ViewRootImpl.java

private int processPointerEvent(QueuedInputEvent q) {            final MotionEvent event = (MotionEvent)q.mEvent;            mAttachInfo.mUnbufferedDispatchRequested = false;            final View eventTarget =                    (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?                            mCapturingView : mView;            mAttachInfo.mHandlingPointerEvent = true;            boolean handled = eventTarget.dispatchPointerEvent(event);            maybeUpdatePointerIcon(event);            mAttachInfo.mHandlingPointerEvent = false;            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {                mUnbufferedInputDispatch = true;                if (mConsumeBatchedInputScheduled) {                    scheduleConsumeBatchedInputImmediately();                }            }            return handled ? FINISH_HANDLED : FORWARD;        }

View.java

 public final boolean dispatchPointerEvent(MotionEvent event) {        if (event.isTouchEvent()) {            return dispatchTouchEvent(event);        } else {            return dispatchGenericMotionEvent(event);        }    }

DecorView.java

@Override    public boolean dispatchTouchEvent(MotionEvent ev) {        final Window.Callback cb = mWindow.getCallback();        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);}
如果还不清楚这个流程的话,好吧,我把调用的backtrack也贴出来一下吧
                      java.lang.RuntimeException                      at com.hxiong.camerademo.CameraDemoActivity.debug(CameraDemoActivity.java:44)                      at com.hxiong.camerademo.CameraDemoActivity.dispatchTouchEvent(CameraDemoActivity.java:39)                      at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:375)                      at android.view.View.dispatchPointerEvent(View.java:10243)                      at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4438)                      at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4306)                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853)                      at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906)                      at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872)                      at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3999)                      at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880)                      at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4056)                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853)                      at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906)                      at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872)                      at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880)                      at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853)                      at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6246)                      at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6220)                      at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6181)                      at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6349)                      at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)                      at android.os.MessageQueue.nativePollOnce(Native Method)                      at android.os.MessageQueue.next(MessageQueue.java:323)                      at android.os.Looper.loop(Looper.java:136)                      at android.app.ActivityThread.main(ActivityThread.java:6119)                      at java.lang.reflect.Method.invoke(Native Method)                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

2)图中WindowState、WindowStateAnimator、SurfaceControl是WindowManagerService管理Surface的模块,前面讲过了Surface只是producer端的封装。这里只是简单将一下apk的ui是怎么绘制出来的,不考虑硬件加速的情况。

(1)通过Surface dequeue出一块可用的buffer

(2)将这块buffer关联到skia 的SkBitmap

(3)再从SkBitmap里抽象出SkCanvas

(4)然后用SkPaint先在SkCanvas上进行绘制

(5)最后真正同步绘制到SkBitmap上,buffer也就被修改了

(6)通过Surface queue出buffer,送给Surfaceflinger去显示

2、SurfaceView

SurfaceView里面最关键的同样是Surface,这个surface跟应用ui用的surface不是同一个,它的创建过程和ViewRootImpl中的surface差不多一样。通过Session.relayout(…)创建出来。一般用它来显示camera的preview或者播放的视频画面,本质上就是把surface(producer端)传给其他模块,让其他模块往这个producer端送数据。当然应用也可以自己在SurfaceView上绘制东西,例如

Surface.lockCanvas();

… //做各种各样的绘制

Surface.unlockCanvasAndPost();

其实这个过程和上面ui的绘制差不多,Surface.lockCanvas()就是去关联skia,用skia提供的接口实现不同功能的绘制,最用通过Surface.unlockCanvasAndPost()真正修改到surface buffer,然后送去surfaceflinger显示。

3、TextureView

这个怎么说好呢,它主要的作用就是把SurfaceTexture收到的数据显示在UI上,所以它一定是会和一个SurfaceTexture关联。在SurfaceTexture初始化的时候,通过BufferQueue创建了producer和consumer,而SurfaceTexture就充当了consumer端,也就是GLConsumer。它一般会将producer提供给其他模块,用于从其他模块获取数据流,然后再通知TextureView去更新,也就是是显示到UI上。

static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,        jint texName, jboolean singleBufferMode, jobject weakThiz){    sp<IGraphicBufferProducer> producer;    sp<IGraphicBufferConsumer> consumer;    BufferQueue::createBufferQueue(&producer, &consumer);    if (singleBufferMode) {        consumer->setMaxBufferCount(1);    }    sp<GLConsumer> surfaceTexture;    if (isDetached) {        surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES,                true, !singleBufferMode);    } else {        surfaceTexture = new GLConsumer(consumer, texName,                GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);    }    if (surfaceTexture == 0) {        jniThrowException(env, OutOfResourcesException,                "Unable to create native SurfaceTexture");        return;    }    surfaceTexture->setName(String8::format("SurfaceTexture-%d-%d-%d",            (isDetached ? 0 : texName),            getpid(),            createProcessUniqueId()));    // If the current context is protected, inform the producer.    if (isProtectedContext()) {        consumer->setConsumerUsageBits(GRALLOC_USAGE_PROTECTED);    }    SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);    SurfaceTexture_setProducer(env, thiz, producer);    jclass clazz = env->GetObjectClass(thiz);    if (clazz == NULL) {        jniThrowRuntimeException(env,                "Can't find android/graphics/SurfaceTexture");        return;    }    sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,            clazz));    surfaceTexture->setFrameAvailableListener(ctx);    SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);}

SurfaceTexture本身并没有提供接口给应用拿Producer送过来的数据,所有应用并没有办法直接那到数据,TextureView通过把它绑定到HardwareLayer,利用Render把数据内容绘制到UI上,当然还有很多其他关联的模块。可以向TextureView设置SurfaceTextureListener,在onSurfaceTextureUpdated()回调的时候通过getBitmap()接口拿到数据。

            textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {            @Override            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {                            }            @Override            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {            }            @Override            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {                return false;            }            @Override            public void onSurfaceTextureUpdated(SurfaceTexture surface) {               Bitmap bitmep= textureView.getBitmap();                // TODO            }        });










原创粉丝点击