- 浏览: 756828 次
文章分类
最新评论
-
bzhao:
你用最小的例子把VPATH 说明白了!
Makefile不支持VPATH的问题 -
qingfeng200468:
【2 + 3的逆波兰表示法为+ 2 3。】这句写错了,应该是波 ...
逆波兰表达式
Android应用程序键盘(Keyboard)消息处理机制分析(四)
上接:Android应用程序键盘(Keyboard)消息处理机制分析(三)
----
4.应用程序注销键盘消息接收通道的过程分析
当Activity窗口创建时,它会向InputManager注册键盘消息接收通道,而当Activity窗口销毁时,它就会向InputManager注销前面注册的键盘消息接收通道了,本节内容就来看看应用程序注销键盘消息接收通道的过程。
当我们按下键盘上的Back键时,当前激活的Activity窗口就会被失去焦点,但是这时候它还没有被销毁,它的状态被设置为Stopped;当新的Activity窗口即将要显示时,它会通知WindowManagerService,这时候WindowManagerService就会处理当前处理Stopped状态的Activity窗口了,要执行的操作就是销毁它们了,在销毁的时候,就会注销它们之前所注册的键盘消息接收通道。
新的Activity窗口通知WindowManagerService它即将要显示的过程比较复杂,但是它与我们本节要介绍的内容不是很相关,因此,这里就略过大部过程了,我们从ActvitiyRecord的windowsVisible函数开始分析。注意,这里的ActivityRecord是新的Activity窗口在ActivityManangerService的代表,而那些处于Stopped状态的Activity窗口
会放在ActivityStack类的一个等待可见的mWaitingVisibleActivities列表里面,事实于,对于那些Stopped状态的Activity窗口来说,它们是等待销毁,而不是等待可见。
像前面一样,我们先来看一张应用程序注销键盘消息接收通道的过程的序列图,然后根据这个序列图来详细分析互一个步骤:
Step 1. ActivityRecord.windowsVisible
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityRecord.java文件中:
- classActivityRecordextendsIApplicationToken.Stub{
- ......
- booleannowVisible;//isthisactivity'swindowvisible?
- booleanidle;//hastheactivitygoneidle?
- ......
- publicvoidwindowsVisible(){
- synchronized(service){
- ......
- if(!nowVisible){
- nowVisible=true;
- if(!idle){
- .......
- }else{
- //Ifthisactivitywasalreadyidle,thenwenowneedto
- //makesureweperformthefullstopofanyactivities
- //thatarewaitingtodoso.Thisisbecausewewon't
- //dothatwhiletheyarestillwaitingforthisoneto
- //becomevisible.
- finalintN=stack.mWaitingVisibleActivities.size();
- if(N>0){
- for(inti=0;i<N;i++){
- ActivityRecordr=(ActivityRecord)
- stack.mWaitingVisibleActivities.get(i);
- r.waitingVisible=false;
- ......
- }
- stack.mWaitingVisibleActivities.clear();
- Messagemsg=Message.obtain();
- msg.what=ActivityStack.IDLE_NOW_MSG;
- stack.mHandler.sendMessage(msg);
- }
- }
- ......
- }
- }
- }
- ......
- }
- finalintN=stack.mWaitingVisibleActivities.size();
- if(N>0){
- for(inti=0;i<N;i++){
- ActivityRecordr=(ActivityRecord)
- stack.mWaitingVisibleActivities.get(i);
- r.waitingVisible=false;
- ......
- }
- stack.mWaitingVisibleActivities.clear();
- Messagemsg=Message.obtain();
- msg.what=ActivityStack.IDLE_NOW_MSG;
- stack.mHandler.sendMessage(msg);
- }
Step 2. ActivityStack.activityIdleInternal
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:
- publicclassActivityStack{
- ......
- finalvoidactivityIdleInternal(IBindertoken,booleanfromTimeout,
- Configurationconfig){
- ......
- ArrayList<ActivityRecord>stops=null;
- ......
- intNS=0;
- ......
- synchronized(mService){
- ......
- //Atomicallyretrievealloftheotherthingstodo.
- stops=processStoppingActivitiesLocked(true);
- NS=stops!=null?stops.size():0;
- ......
- }
- inti;
- ......
- //Stopanyactivitiesthatarescheduledtodosobuthavebeen
- //waitingforthenextonetostart.
- for(i=0;i<NS;i++){
- ActivityRecordr=(ActivityRecord)stops.get(i);
- synchronized(mService){
- if(r.finishing){
- finishCurrentActivityLocked(r,FINISH_IMMEDIATELY);
- }else{
- ......
- }
- }
- }
- ......
- }
- ......
- }
Step 3.ActivityStack.finishCurrentActivityLocked
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:
- publicclassActivityStack{
- ......
- privatefinalActivityRecordfinishCurrentActivityLocked(ActivityRecordr,
- intmode){
- ......
- returnfinishCurrentActivityLocked(r,index,mode);
- }
- privatefinalActivityRecordfinishCurrentActivityLocked(ActivityRecordr,
- intindex,intmode){
- ......
- //makesuretherecordiscleanedoutofotherplaces.
- mStoppingActivities.remove(r);
- mWaitingVisibleActivities.remove(r);
- ......
- finalActivityStateprevState=r.state;
- r.state=ActivityState.FINISHING;
- if(mode==FINISH_IMMEDIATELY
- ||prevState==ActivityState.STOPPED
- ||prevState==ActivityState.INITIALIZING){
- //Ifthisactivityisalreadystopped,wecanjustfinish
- //itrightnow.
- returndestroyActivityLocked(r,true)?null:r;
- }else{
- ......
- }
- returnr;
- }
- ......
- }
Step 4.ActivityStack.destroyActivityLocked
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:
- publicclassActivityStack{
- ......
- finalbooleandestroyActivityLocked(ActivityRecordr,
- booleanremoveFromApp){
- ......
- booleanremovedFromHistory=false;
- ......
- finalbooleanhadApp=r.app!=null;
- if(hadApp){
- ......
- try{
- ......
- r.app.thread.scheduleDestroyActivity(r,r.finishing,
- r.configChangeFlags);
- }catch(Exceptione){
- ......
- }
- ......
- }else{
- ......
- }
- ......
- returnremovedFromHistory;
- }
- ......
- }
- r.app.thread.scheduleDestroyActivity(r,r.finishing,
- r.configChangeFlags);
Step 5.ApplicationThread.scheduleDestroyActivity
这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:
- publicfinalclassActivityThread{
- ......
- privatefinalclassApplicationThreadextendsApplicationThreadNative{
- ......
- publicfinalvoidscheduleDestroyActivity(IBindertoken,booleanfinishing,
- intconfigChanges){
- queueOrSendMessage(H.DESTROY_ACTIVITY,token,finishing?1:0,
- configChanges);
- }
- ......
- }
- ......
- }
Step 6.ActivityThread.handleDestroyActivity
这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:
- publicfinalclassActivityThread{
- ......
- privatefinalvoidhandleDestroyActivity(IBindertoken,booleanfinishing,
- intconfigChanges,booleangetNonConfigInstance){
- ......
- ActivityClientRecordr=performDestroyActivity(token,finishing,
- configChanges,getNonConfigInstance);
- if(r!=null){
- WindowManagerwm=r.activity.getWindowManager();
- Viewv=r.activity.mDecor;
- if(v!=null){
- ......
- if(r.activity.mWindowAdded){
- wm.removeViewImmediate(v);
- }
- ......
- }
- ......
- }
- ......
- }
- ......
- }
Step 7.LocalWindowManager.removeViewImmediate
这个函数定义在frameworks/base/core/java/android/view/Window.java文件中:
- publicabstractclassWindow{
- ......
- privateclassLocalWindowManagerimplementsWindowManager{
- ......
- publicfinalvoidremoveViewImmediate(Viewview){
- mWindowManager.removeViewImmediate(view);
- }
- ......
- privatefinalWindowManagermWindowManager;
- }
- ......
- }
Step 8.WndowManagerImpl.removeViewImmediate
这个函数定义在frameworks/base/core/java/android/view/WindowManagerImpl.java文件中:
- publicclassWindowManagerImplimplementsWindowManager{
- ......
- publicvoidremoveViewImmediate(Viewview){
- synchronized(this){
- intindex=findViewLocked(view,true);
- ViewRootroot=mRoots[index];
- ......
- root.die(true);
- ......
- }
- }
- ......
- }
Step 9. ViewRoot.die
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- publicvoiddie(booleanimmediate){
- if(immediate){
- doDie();
- }else{
- ......
- }
- }
- ......
- }
Step 10.ViewRoot.doDie
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- voiddoDie(){
- ......
- synchronized(this){
- ......
- if(mAdded){
- mAdded=false;
- dispatchDetachedFromWindow();
- }
- }
- }
- ......
- }
Step 11.ViewRoot.ispatchDetachedFromWindow
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- voiddispatchDetachedFromWindow(){
- ......
- if(mInputChannel!=null){
- if(mInputQueueCallback!=null){
- ......
- }else{
- InputQueue.unregisterInputChannel(mInputChannel);
- }
- }
- try{
- sWindowSession.remove(mWindow);
- }catch(RemoteExceptione){
- }
- ......
- }
- ......
- }
我们先来看注销注册在应用程序这一侧的Client端InputChannel,然后再回过头来分析注销注册在InputManager这一侧的Server端InputChannel。
Step 12.InputQueue.unregisterInputChannel
这个函数定义在frameworks/base/core/java/android/view/InputQueue.java文件中:
- publicfinalclassInputQueue{
- ......
- publicstaticvoidunregisterInputChannel(InputChannelinputChannel){
- ......
- synchronized(sLock){
- ......
- nativeUnregisterInputChannel(inputChannel);
- }
- }
- ......
- }
Step 13.InputQueue.nativeUnregisterInputChannel
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:
- staticvoidandroid_view_InputQueue_nativeUnregisterInputChannel(JNIEnv*env,jclassclazz,
- jobjectinputChannelObj){
- status_tstatus=gNativeInputQueue.unregisterInputChannel(env,inputChannelObj);
- ......
- }
Step 14.NativeInputQueue.unregisterInputChannel
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:
- status_tNativeInputQueue::unregisterInputChannel(JNIEnv*env,jobjectinputChannelObj){
- sp<InputChannel>inputChannel=android_view_InputChannel_getInputChannel(env,
- inputChannelObj);
- ......
- {//acquirelock
- AutoMutex_l(mLock);
- ssize_tconnectionIndex=getConnectionIndex(inputChannel);
- ......
- sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
- connection->status=Connection::STATUS_ZOMBIE;
- connection->looper->removeFd(inputChannel->getReceivePipeFd());
- env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
- connection->inputHandlerObjGlobal=NULL;
- ......
- }//releaselock
- ......
- returnOK;
- }
- ssize_tconnectionIndex=getConnectionIndex(inputChannel);
- ......
- sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
- connection->looper->removeFd(inputChannel->getReceivePipeFd());
最后将Connection对象中的回调对象inputHandlerOjbGlobal对象删除:
- env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
- connection->inputHandlerObjGlobal=NULL;
注册在应用程序这一侧的Client端InputChannel被注销以后,回到前面的Step 11中,我们继续分析注销注册在InputManager这一侧的Server端InputChannel。
Step 15. WindowManagerService.Session.remove
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:
- publicclassWindowManagerServiceextendsIWindowManager.Stub
- implementsWatchdog.Monitor{
- ......
- privatefinalclassSessionextendsIWindowSession.Stub
- implementsIBinder.DeathRecipient{
- ......
- publicvoidremove(IWindowwindow){
- removeWindow(this,window);
- }
- ......
- }
- ......
- }
这个函数只是简单地调用其外部类WindowManagerService的removeWindow函数来进一步执行操作。
Step 16.WindowManagerService.removeWindow
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:
- publicclassWindowManagerServiceextendsIWindowManager.Stub
- implementsWatchdog.Monitor{
- ......
- publicvoidremoveWindow(Sessionsession,IWindowclient){
- synchronized(mWindowMap){
- WindowStatewin=windowForClientLocked(session,client,false);
- if(win==null){
- return;
- }
- removeWindowLocked(session,win);
- }
- }
- ......
- }
回忆一下前面我们在分析应用程序注册键盘消息管道的过程时,在Step 11(WindowManagerService.addWindow)中,WindowManagerService为这个即将要激活的Activity窗口创建了一个WindowState对象win,创建的时候,使用了从ViewRoot中传过来的两个参数,分别是一个Session对象session和一个IWindow对象client。
在这个函数中,ViewRoot传过来的两个参数session和client和上面说的两个参数是一致的,因此,这个函数首先通过参数session和client得到一个WindowState对象win,然后调用removeWindowLocked来把它从WindowManagerService删除。
Step 17.WindowManagerService.removeWindowLocked
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:
- publicclassWindowManagerServiceextendsIWindowManager.Stub
- implementsWatchdog.Monitor{
- ......
- publicvoidremoveWindowLocked(Sessionsession,WindowStatewin){
- ......
- win.disposeInputChannel();
- ......
- }
- ......
- }
Step 18. WindowState.disposeInputChannel
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:
- publicclassWindowManagerServiceextendsIWindowManager.Stub
- implementsWatchdog.Monitor{
- ......
- privatefinalclassWindowStateimplementsWindowManagerPolicy.WindowState{
- ......
- voiddisposeInputChannel(){
- if(mInputChannel!=null){
- mInputManager.unregisterInputChannel(mInputChannel);
- mInputChannel.dispose();
- mInputChannel=null;
- }
- }
- ......
- }
- ......
- }
Step 19. InputManager.unregisterInputChannel
这个函数定义在frameworks/base/services/java/com/android/server/InputManager.java文件中:
- publicclassInputManager{
- ......
- publicvoidunregisterInputChannel(InputChannelinputChannel){
- ......
- nativeUnregisterInputChannel(inputChannel);
- }
- ......
- }
Step 20.InputManager.nativeUnregisterInputChannel
这个函数定义在frameworks/base/services/jni/com_android_server_InputManager.cpp文件中:
- staticvoidandroid_server_InputManager_nativeUnregisterInputChannel(JNIEnv*env,jclassclazz,
- jobjectinputChannelObj){
- ......
- sp<InputChannel>inputChannel=android_view_InputChannel_getInputChannel(env,
- inputChannelObj);
- ......
- status_tstatus=gNativeInputManager->unregisterInputChannel(env,inputChannel);
- ......
- }
Step 21.NativeInputManager.unregisterInputChannel
这个函数定义在frameworks/base/services/jni/com_android_server_InputManager.cpp文件中:
- status_tNativeInputManager::unregisterInputChannel(JNIEnv*env,
- constsp<InputChannel>&inputChannel){
- ......
- returnmInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
- }
Step 22.InputDispatcher.unregisterInputChannel
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- status_tInputDispatcher::unregisterInputChannel(constsp<InputChannel>&inputChannel){
- ......
- {//acquirelock
- AutoMutex_l(mLock);
- ssize_tconnectionIndex=getConnectionIndexLocked(inputChannel);
- ......
- sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
- ......
- mLooper->removeFd(inputChannel->getReceivePipeFd());
- .....
- }//releaselock
- ......
- returnOK;
- }
- ssize_tconnectionIndex=getConnectionIndexLocked(inputChannel);
- ......
- sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
这样,应用程序注销键盘消息接收通道的过程就分析完成了,整个应用程序键盘消息处理机制也分析完成了,这是一个比较复杂的过程,要完全理解它还需要花费一些努力和时间,不过,理解了这个过程之后,对Android应用程序框架层的理解就更进一步了。
转自:老罗的Android应用程序键盘(Keyboard)消息处理机制分析
相关推荐
Android应用程序键盘(Keyboard)消息处理机制分析
详细讲解了Android应用程序键盘消息处理机制,从Java层一直到C++层与系统对接,全部涵盖
一个牛人写的博客,虽然名为浅谈,实际非常详尽 从注册到事件上传都有,复制下来竟然有... 收一元辛苦费,没积分的同学自己看博客吧: http://www.itivy.com/android/archive/2011/10/25/android-keyboard-message.html
emoji-keyboard, 为Android应用程序提供表情符号键盘实现的库 Android表情键盘为Android应用程序提供表情符号键盘实现的库 Showcase 快速安装dependencies { compile 'br.com.instachat:emoji-library
Android自定义软键盘,在Keyboard的基础上稍微修改了一下,从键盘焦点效果到键盘布局,都是新风格。
Keyboard 解决android表情键盘闪动问题
《游戏键盘 GameKeyboard》对全安卓游戏的虚拟键盘逆向映射到Xperia Play实体键的实现。可以实现安卓游戏中的虚拟键盘映射到实体键上,可以编辑映射的虚拟键位置,使其对位在屏幕的虚拟控制键上,实体按钮才能产生...
Android自定义软键盘KeyboardView
custom_keyboard android 自定义键盘
Delphi XE 开发Android虚拟键盘 ,源码文件:FMX.VirtualKeyboard.Android
这篇文章是介绍Android中自定义键盘的一些套路,通过定义一个数字键盘为例,本篇的文章语言是基于Kotlin实现的,如果还没有用或者不熟悉该语言的同学,可以自己补习,我之前也写过入门文章。 效果图 github:源码...
keyboard-layout-editor, Web应用程序实现键盘布局的&编辑 keyboard-layout-editorKeyboard-layout-editor.com 是一个网络应用程序,可以编辑键盘布局。换句话说,。每个物理键的位置和外观。创建这个应用程序的动机...
PC 键盘驱动程序的工作流程可以分为四个步骤:键盘初始化、键盘中断响应、键盘后端处理和键盘数据传递。 首先,键盘初始化是 PC 键盘驱动程序的第一步。在这个步骤中,驱动程序会调用键盘初始化函数 kbd_init(),该...
keyboard-dismisser一个实现点击任何键盘外的部分来取消键盘的Android库
android-xnumberkeyboard, Android number keyboard view. Android自定义的数字键盘。
Android表情符号键盘一个为Android应用程序提供表情符号键盘实现的库 这是由项目创建的。repositories {...maven { url '...
Microchip keyboard firmware键盘固件程序 pic18fx
iPhone 5s Keyboard iOS 7iPhone 5s Keyboard iOS 7是一款高效实用的应用程序,每一位Android用户都可以通过它将自己Android设备中的键盘替换成为iPhone 5s的键盘,简单便捷。 你需要激活设备中的键盘才可以使用这...
键盘修复工具KeyBoard KeyBoard
基于emWin的全键盘控件,提供一个480x272大小的完整窗口,窗口内包含标准键盘及输入窗口