头条Android高级开发岗二面:按下手机的-Home-键,有哪些动作和事件发生?(1)

最后

那我们该怎么做才能做到年薪60万+呢,对于程序员来说,只有不断学习,不断提升自己的实力。我之前有篇文章提到过,感兴趣的可以看看,到底要学习哪些知识才能达到年薪60万+。

通过职友集数据可以查看,以北京 Android 相关岗位为例,其中 【20k-30k】 薪酬的 Android 工程师,占到了整体从业者的 30.8%!

北京 Android 工程师「工资收入水平 」

今天重点内容是怎么去学,怎么提高自己的技术。

1.合理安排时间

2.找对好的系统的学习资料

3.有老师带,可以随时解决问题

4.有明确的学习路线

当然图中有什么需要补充的或者是需要改善的,可以在评论区写下来,一起交流学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

}

主要是调用 nativeInit 方法传入一个消息队列,nativeInit 方法是为了去初始化一些 native 对象。最终是为了 new 一个 native 层的 InputManager 。 调用链如(想要了解详情的同学可以在相应的源码类里查看):

new InputManagerService() // InputManagerService.java
-> nativeInit(…, queue) // com_android_server_input_InputManagerService.cpp
-> new NativeInputManager(…, looper) // com_android_server_input_InputManagerService.cpp
-> new InputManager(eventHub, …) //InputManager.cpp

重点就在这个 InputManager 里

InputManager::InputManager(…) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}

void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

我们可以看到,在 InputManager 里准备好了 mReader、mDispatcher,以及相关的两个线程,那么接下来当然就是把线程跑起来,好去读事件和分发事件。

启动事件读取和分发线程的调用链如下:

SystemServer.startOtherServices()
-> inputManagerService.start()
-> nativeStart() // com_android_server_input_InputManagerService.cpp
-> InputManager.start() // InputManager.cpp

最后的这个 start 方法很简单,就是把两个线程跑起来

status_t InputManager::start() {
status_t result = mDispatcherThread->run(“InputDispatcher”, PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run(“InputReader”, PRIORITY_URGENT_DISPLAY);
}

至此,事件处理工作所需要的对象和线程都已经准备好了。前面那些代码看完记不住就算了,记住这句话:SystemServer 启动 IMS 时,会创建一个 native 的 InputManager 对象,这个 InputManager 会通过 mReader 不断读事件,再通过 mDispatcher 不断分发事件

接下来我们看下,事件是怎么读取和分发的。

事件的读取

InputReaderThread 等待按键消息到来,该 Thread 在 threadLoop 中无尽的调用 InputReader 的 loopOnce 方法。

bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}

在 loopOnce 方法中会通过 EventHub 来获取事件,并放入 buffer 中:

void InputReader::loopOnce() {
// EventHub 从驱动读取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

if (count) {
// 获取的事件是 RawEvent,需要处理成 KeyEvent、MotionEvent 等各种类型等
processEventsLocked(mEventBuffer, count);
}
// 将队列中事件刷给监听器,监听器实际上就是 InputDispatcher 事件分发器。
mQueuedListener->flush();
}

InputDispatcher 收到事件后调用,如果是 KeyEvent 会调用 notifyKey,如果是 MotionEvent 则会调用 notifyMotion

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action,
flags, keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);

// 通过 NatvieInputManager 在 Event 入队前做一些处理
mPolicy->interceptKeyBeforeQueueing(&event, /byref/ policyFlags);


KeyEntry* newEntry = new KeyEntry(args->eventTime, args->source,
args->action, flags, keyCode,…)
// 事件放入队尾
needWake = enqueueInboundEventLocked(newEntry);
}

以上,便是 InputReader 获取到设备事件通知 InputDispatcher 并存放到事件队列中的流程。

事件的分发

下面将介绍 InputDispatcher 如何从事件队列中读取事件并分发出去。

首先在 InputDispatcherThread 的 threadLoop 中无尽的调用 dispatchOnce 方法

bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}

该方法两个功能:

  • 调用 dispatchOnceInnerLocked 分发事件;
  • 调用 runCommandsLockedInterruptible 来处理 CommandQueue 中的命令,出队并处理,直到队列为空。

void InputDispatcher::dispatchOnce() {
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}

}

在 dispatchOnceInnerLocked 中会处理多种类型的事件,这里关注按键类型的(其他如触摸,设备重置等事件流程稍有区别)。一通调用后到 PhoneWindowManager , 终于回到 java 了,

InputDispatcher::dispatchOnceInnerLocked
-> dispatchKeyLocked
-> doInterceptKeyBeforeDispatchingLockedInterruptible
-> NativeInputManager.interceptKeyBeforeDispatching
-> PhoneWindowManager.interceptKeyBeforeDispatching

// 以下 NativeInputManager.doInterceptKeyBeforeDispatchingLockedInterruptible 的部分代码
nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
&event, entry->policyFlags);
if (delay < 0) {
// Home 事件将被拦截
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
}
// 未被拦截的继续处理分发,本篇暂不分析

PhoneWindowManager

话不多说,继续看代码,离胜利不远了!源码的注释写得很清楚,我这边就不翻译了。真的不是因为懒,是想让你们提高点英语阅读水平 。(-> <-)

public long interceptKeyBeforeDispatching(KeyEvent event, …) {
// First we always handle the home key here, so applications
// can never break it, although if keyguard is on, we do let
// it handle it, because that gives us the correct 5 second
// timeout.
if (keyCode == KeyEvent.KEYCODE_HOME) {
// If we have released the home key, and didn’t do anything else
// while it was pressed, then it is time to go home!
if (!down) {
cancelPreloadRecentApps();
mHomePressed = false;

// Delay handling home if a double-tap is possible.
if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
mHomeDoubleTapPending = true;
mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
ViewConfiguration.getDoubleTapTimeout());
return -1;
}
handleShortPressOnHome(); //短按

//-1 调用处的事件结果就会赋值 INTERCEPT_KEY_RESULT_SKIP
return -1;
}

// Remember that home is pressed and handle special actions.
if (repeatCount == 0) {
mHomePressed = true;
if (mHomeDoubleTapPending) {
handleDoubleTapOnHome();//双击
} else if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
preloadRecentApps();//最近 app
}
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
if (!keyguardOn) {
handleLongPressOnHome(event.getDeviceId());//长按
}
}
return -1;
}

尾声

以薪资待遇为基础,以发展为最终目标,要在高薪资的地方,谋求最好的发展!

下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

2)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值