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 } });
- Android UI简介
- Android之UI简介
- android ui 简介
- Android目录介绍&UI简介
- android UI 相关常用类简介
- android UI 相关常用类简介
- android UI 相关常用类简介
- android UI 相关常用类简介
- android UI 相关常用类简介
- 【转】android UI 相关常用类简介
- android--UI相关常用类简介
- Appium Android UI自动化简介 + 实战
- Android UI框架 Android UI控件类简介 android5大布局详解
- 轉載 :【转】android UI 相关常用类简介
- android UI之View和ViewGroups简介
- Android ActivityThread(主线程或UI线程)简介
- Android ActivityThread(主线程或UI线程)简介
- Android ActivityThread(主线程或UI线程)简介
- JAVA 面试题(转)
- 弗洛伊德(Floyd)算法比较N个数之间的大小
- JQ实现手风琴特效
- POI 通用导出Excel(.xls,.xlsx)
- #UWP#期中项目,做一个网络电视
- android ui 简介
- 项目的概要设计过程
- Scala---字符串
- 但行好事 莫问前程
- UIWindow的windowLevel属性
- 用户访问页面js执行工作流示例一
- add 2 numbers
- 单例模式的八种写法比较
- AngularJS Eclipse 插件