当前位置: 首页 > news >正文

佛山顺德网站建设公司哪家好二级网站怎么建设

佛山顺德网站建设公司哪家好,二级网站怎么建设,简单的网站建设方案,网站的栏目结构简图怎么做概述 上一个章节,我们讲解了App如何使用InputChannel通道与input系统服务建立通信的桥梁的过程,本章我们讲述App如何从input系统服务中获取上报的输入事件,也就是我们本章讲述的InputEventReceiver。 本文涉及的源码路径 frameworks/base/c…

概述

        上一个章节,我们讲解了App如何使用InputChannel通道与input系统服务建立通信的桥梁的过程,本章我们讲述App如何从input系统服务中获取上报的输入事件,也就是我们本章讲述的InputEventReceiver。

本文涉及的源码路径

frameworks/base/core/java/android/view/InputChannel.java

frameworks/base/core/java/android/view/ViewRootImpl.java

frameworks/base/core/jni/android_view_InputChannel.cpp

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

frameworks/base/core/jni/com_android_server_input_InputManagerService.cpp

frameworks/base/services/core/java/com/android/server/wm/Session.java

frameworks/base/core/java/android/view/WindowState.java

WindowInputEventReceiver事件接收器

上一章节,我们讲述了当App初始化完成InputChannel后,会创建一个事件接收器,如下所示:

mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());

其中 WindowInputEventReceiver是InputEventReceiver的子类,实现如下所示:

final class WindowInputEventReceiver extends InputEventReceiver {public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {super(inputChannel, looper);}@Overridepublic void onInputEvent(InputEvent event) {enqueueInputEvent(event, this, 0, true);}@Overridepublic void onBatchedInputEventPending() {if (mUnbufferedInputDispatch) {super.onBatchedInputEventPending();} else {scheduleConsumeBatchedInput();}}@Overridepublic void dispose() {unscheduleConsumeBatchedInput();super.dispose();}}

从中我们可以知道,核心实现是InputEventReceiver,因此接下来我们重点讲述InputEventReceiver的实现。

InputEventReceiver 输入事件接收器

InputEventReceiver的类,我们主要讲述核心方法的实现,如下所示:

public abstract class InputEventReceiver {......private long mReceiverPtr;private InputChannel mInputChannel;private MessageQueue mMessageQueue;// Map from InputEvent sequence numbers to dispatcher sequence numbers.private final SparseIntArray mSeqMap = new SparseIntArray();private static native long nativeInit(WeakReference<InputEventReceiver> receiver,InputChannel inputChannel, MessageQueue messageQueue);private static native void nativeDispose(long receiverPtr);private static native void nativeFinishInputEvent(long receiverPtr, int seq, boolean handled);private static native boolean nativeConsumeBatchedInputEvents(long receiverPtr,long frameTimeNanos);public InputEventReceiver(InputChannel inputChannel, Looper looper) {......mInputChannel = inputChannel;mMessageQueue = looper.getQueue();mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),inputChannel, mMessageQueue);}public void onInputEvent(InputEvent event) {finishInputEvent(event, false);}public final void finishInputEvent(InputEvent event, boolean handled) {if (event == null) {throw new IllegalArgumentException("event must not be null");}if (mReceiverPtr == 0) {Log.w(TAG, "Attempted to finish an input event but the input event "+ "receiver has already been disposed.");} else {int index = mSeqMap.indexOfKey(event.getSequenceNumber());if (index < 0) {Log.w(TAG, "Attempted to finish an input event that is not in progress.");} else {int seq = mSeqMap.valueAt(index);mSeqMap.removeAt(index);nativeFinishInputEvent(mReceiverPtr, seq, handled);}}event.recycleIfNeededAfterDispatch();}// Called from native code.@SuppressWarnings("unused")private void dispatchInputEvent(int seq, InputEvent event) {mSeqMap.put(event.getSequenceNumber(), seq);onInputEvent(event);}// Called from native code.@SuppressWarnings("unused")private void dispatchBatchedInputEventPending() {onBatchedInputEventPending();}public static interface Factory {public InputEventReceiver createInputEventReceiver(InputChannel inputChannel, Looper looper);}
}

InputEventReceiver的初始化

InputEventReceiver的构造方法实现,如下:

public InputEventReceiver(InputChannel inputChannel, Looper looper) {......mInputChannel = inputChannel;mMessageQueue = looper.getQueue();mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),inputChannel, mMessageQueue);}

该方法的初始化使用了App自己的inputChannel通道和App的Looper消息队列,然后调用JNI方法完成最终的初始化,如下所示:

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,jobject inputChannelObj, jobject messageQueueObj) {sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,inputChannelObj);if (inputChannel == NULL) {jniThrowRuntimeException(env, "InputChannel is not initialized.");return 0;}sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);if (messageQueue == NULL) {jniThrowRuntimeException(env, "MessageQueue is not initialized.");return 0;}sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,receiverWeak, inputChannel, messageQueue);status_t status = receiver->initialize();if (status) {String8 message;message.appendFormat("Failed to initialize input event receiver.  status=%d", status);jniThrowRuntimeException(env, message.string());return 0;}receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the objectreturn reinterpret_cast<jlong>(receiver.get());
}

nativeInit方法主要完成如下的逻辑:

1、找到java层的InputChannel对象对应的Native层的C++对象inputChannel;

2、找到java层的messageQueue对象对应的Native层的C++对象messageQueue;

3、调用NativeInputEventReceiver的initialize完成初始化;

我们继续讲解NativeInputEventReceiver的实现,如下所示:

class NativeInputEventReceiver : public LooperCallback {
public:NativeInputEventReceiver(JNIEnv* env,jobject receiverWeak, const sp<InputChannel>& inputChannel,const sp<MessageQueue>& messageQueue);status_t initialize();......virtual int handleEvent(int receiveFd, int events, void* data);
};

NativeInputEventReceiver继承LooperCallback, 并重载实现了handleEvent。我们这里重点提及到LooperCallback,是因为App获取Input输入事件是通过监控inputChannel通道,并通过LooperCallback实现输入事件的获取,监控代码如下所示:

void NativeInputEventReceiver::setFdEvents(int events) {if (mFdEvents != events) {mFdEvents = events;int fd = mInputConsumer.getChannel()->getFd();if (events) {mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);} else {mMessageQueue->getLooper()->removeFd(fd);}}
}

该接口的实现,我加入了对ALOOPER_EVENT_INPUT事件类型的监控,InputDispatcher上报的输入事件会触发ALOOPER_EVENT_INPUT事件,并最终调用到NativeInputEventReceiver中的handleEvent方法。关于Looper的实现,我们这里不详细展开,感兴趣的同学可以,自行去阅读AOSP源码。

App Input输入事件的获取

当InputDispatcher上报事件时,将输入事件写入InputChannel后,最终会触发NativeInputEventReceiver中的handleEvent执行,如下所示:

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {......if (events & ALOOPER_EVENT_INPUT) {JNIEnv* env = AndroidRuntime::getJNIEnv();status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");return status == OK || status == NO_MEMORY ? 1 : 0;}......return 1;
}

我们只保留了InputDispatcher上报事件时的触发回调代码,然后继续调用consumeEvents接口,如下所示:

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {......for (;;) {uint32_t seq;InputEvent* inputEvent;status_t status = mInputConsumer.consume(&mInputEventFactory,consumeBatches, frameTime, &seq, &inputEvent);......if (!skipCallbacks) {......switch (inputEvent->getType()) {case AINPUT_EVENT_TYPE_KEY:if (kDebugDispatchCycle) {ALOGD("channel '%s' ~ Received key event.", getInputChannelName());}inputEventObj = android_view_KeyEvent_fromNative(env,static_cast<KeyEvent*>(inputEvent));break;case AINPUT_EVENT_TYPE_MOTION: {if (kDebugDispatchCycle) {ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());}MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {*outConsumedBatch = true;}inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);break;}default:assert(false); // InputConsumer should prevent this from ever happeninginputEventObj = NULL;}if (inputEventObj) {env->CallVoidMethod(receiverObj.get(),gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);} else {ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());skipCallbacks = true;}}......}
}

consumeEvents实现比较复杂,涉及到的逻辑比较多,为了简化描述,我们只保留首次上报输入事件的处理,主要实现逻辑如下所示:

1、mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent);获取事件;

2、根据不同的事件类型,封装为一个inputEventObj对象;

3、调用InputEventReceiver的java方法env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);正式开始向App上报输入事件;

调用InputEventReceiver的dispatchInputEvent如下所示:

// Called from native code.@SuppressWarnings("unused")private void dispatchInputEvent(int seq, InputEvent event) {mSeqMap.put(event.getSequenceNumber(), seq);onInputEvent(event);}

最终调用到了 WindowInputEventReceiver子类的onInputEvent方法,如下所示:

 final class WindowInputEventReceiver extends InputEventReceiver {public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {super(inputChannel, looper);}@Overridepublic void onInputEvent(InputEvent event) {enqueueInputEvent(event, this, 0, true);}......}

继续调用enqueueInputEvent,如下所示:

void enqueueInputEvent(InputEvent event,InputEventReceiver receiver, int flags, boolean processImmediately) {adjustInputEventForCompatibility(event);QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);......QueuedInputEvent last = mPendingInputEventTail;if (last == null) {mPendingInputEventHead = q;mPendingInputEventTail = q;} else {last.mNext = q;mPendingInputEventTail = q;}mPendingInputEventCount += 1;Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,mPendingInputEventCount);if (processImmediately) {doProcessInputEvents();} else {scheduleProcessInputEvents();}}

1、将上报的输入事件加入到处理队列中;

2、调用doProcessInputEvents立即开始App对输入事件的处理,我们在后续文章进行讲解。这里不再叙述。

总结

本文讲述了App通过注册输入事件接收器的方式,当InputDispacther上报输入事件时,通过Looper的回调机制App获取到了事件,并通过doProcessInputEvents接口,正式开启App对input事件的处理。

http://www.dtcms.com/a/421694.html

相关文章:

  • 大城 网站常见的网站推广方式
  • vs2019可以做网站吗关键词优化需要从哪些方面开展?
  • 美发网站源码徐州网站开发多少钱
  • 网红网站建设官网app开发公司有哪些
  • 电子商务网站建设服务模式论文wordpress 用的什么框架
  • 响应式网站 appwordpress改登录路径
  • 用python做网站我那些wordpress标签描述代码
  • 江西临川建设集团有限公司网站少儿编程平台
  • 信息发布网站建设2023年央选职位表
  • 广州网站建设企业武义公司网站建设
  • 网站制作计划书网址域名ip查询子域名解析
  • 某网站seo诊断分析上海缔客网站建设公司
  • 陕西省建设厅申报网站wordpress建站dedecms
  • 北京 外贸型网站建设抖音代运营朋友圈文案
  • 建设银行申请信用卡网站腐女做喜欢的网站
  • 编写网站策划方案公众号怎么开通收费功能
  • 有没有什么做h5的网站最好的网站统计
  • 网站开发的三个流程网站建设推广优化招聘模板
  • mvc网站开发 案例视频呼市賽罕区信息网站做一顿饭工作
  • 食品营销网站建设调查问卷做公众号主页面的有哪些网站
  • 网站升级维护中 模板扬中网站建设怎么样
  • 哪个学校有网站建设培训机构好还是学校好
  • 中国最大网站建设商推荐知乎wordpress 行间距
  • 谁有手机网站发几个吧天娇易业网站建设公司
  • 成都地区网站开发成本湖南网站建设 搜搜磐石网络
  • 湖州童装网站海西州公司网站建设
  • php网站安装包制作seo优化策略
  • 营销型企业网站优化百度搜索引擎排名
  • 如何构思公司网站广州网站建设电话咨询
  • 兰州做网站的公司网站用品哪里进货好