最近在狀態列上面添加了一些系統常用的按鍵,用的比較多的,Home, Menu, Back三個按鍵,分別類比物理按鍵按下時的消息,參考下面兩篇文章,可以實現在狀態列上添加自訂的按鍵

 

1.在android的狀態列(statusbar)中增加menu,home和back快速鍵的方法

HTTP://blogold.chinaunix.net/u2/78893/showart_2349971.html

2.在android的狀態列(statusbar)中增加menu,home和back快速鍵的方法,及按鍵延遲原因分析

HTTP://hi.baidu.com/tigerpan/blog/item/63caae81b57580b16c811937.html




但是在狀態列上面點擊按鈕的時候,卻經常出現鎖死,假死的情況,在第二篇文章的時候,提到,






我們先看一下執行流程
在com.android.server.WindowManagerService.injectKeyEvent(KeyEvent, boolean)函數中我們可以看到實際上是調用dispatchKey(newEvent, pid, uid)函數,這個dispatchKey函數中:

 

需要先找到當前的焦點focusObj(focusObj:WindowState 就是在維護視窗ViewRoot與WindowManagerService之前的關聯,這二者的通信都在WindowState中可以找到);再用focusObj把KeyEvent傳遞給當前焦點視窗。但在傳遞之前會先調用mKeyWaiter.waitForNextEventTarget()函數等待當前焦點處理完上一次事件(這包括KeyEvent,MotionEvent...等),如何判斷是否處理完上一次事件, 用if (mFinished && !mDisplayFrozen) if (targetWin != null)這兩個if語句判斷,而最關鍵就是這個mFinished ,這裡還得查看ViewRoot,在ViewRoot中分發事件後會調用sWindowSession.finishKey(mWindow);告訴WindowManagerService,在doFinishedKeyLocked()函數中將mFinished = true,如果mFinished不為true,則會wait(curTimeout),這就是出現停頓的直接原因






通過列印Log顯示是我們的KeyEvent.Action_Down事件一直不能mFinished,這就要跟蹤ViewRoot,發現每次在類比的KeyEvent.Action_Down事件的Message根本不能被處理,原因是StatusBarView的TouchEvent沒有處理完成,並且與類比的KeyEvent.Action_Down事件在MessageQueue的next函數中卡住了而ViewRoot本身就是一個Handler,大量的Message從此經過,而StatusBar的ViewRoot既要處理Touch事件也要處理類比按鍵,就出現了這種競態鎖死的現象。

 

延遲發送類比的KeyEvent是我目前採用的解決方式,上面的例子中sendKey函數已經體現




大概就是按鍵點擊的時候(我自己個人理解),如果在onClick事件裡面立刻直接發送KeyEvent的話,會導致onClick的消息處理無法正常返回,從而導致後面的消息也無法被獲取處理,這是產生假死停頓的原因,所以參考上面的方法,新創建一個執行緒,延時發送KeyEvent(我直接用文2的方法問題也沒有得到很好的解決).

 private void sendVKeyDelay(int key) {
  final int keyCode = key;
  Thread sendKeyDelay = new Thread(){
   public void run() {
    try {
     Thread.sleep(100);
     
     long now = SystemClock.uptimeMillis();
     KeyEvent keyDown = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
       keyCode, 0);
     IWindowManager wm = IWindowManager.Stub.asInterface(
       ServiceManager.getService("window"));
     wm.injectKeyEvent(keyDown, false);
     
     KeyEvent keyUp = new KeyEvent(now, now, KeyEvent.ACTION_UP,
       keyCode, 0);
     wm.injectKeyEvent(keyUp, false);
    } catch (InterruptedException e) {
     e.printStackTrace();
    } catch (RemoteException e) {
     e.printStackTrace();
    }
   }
  };
  sendKeyDelay.start();
 }

 

 

FROM:http://blog.csdn.net/yao_guet/article/details/6366056

創作者介紹

資訊園

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()