最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android開發(fā)input問題解決分析

 更新時(shí)間:2022年11月23日 10:36:51   作者:咖啡你沖不沖  
這篇文章主要為大家介紹了Android開發(fā)input問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

Android Input

Android Input指的是輸入事件,主要是觸摸滑動(dòng),當(dāng)然還包括類似藍(lán)牙外設(shè)的輸入。Input涉及到的主要模塊

  • EventHub :對(duì)輸入事件進(jìn)行映射
  • InputReader : 收集input事件
  • InputDispatcher : 將事件分發(fā)到上層
  • InputManager : framework中對(duì)input事件的接收和分發(fā)
  • WMS : 管理窗口,收集和分發(fā)input事件

本篇主要以framework的視角來debug input問題,介紹input的資料已經(jīng)很多了,所以不講input傳遞流程和機(jī)制,只看如何去解決問題。

從framework的視角,首先我們要排查input driver的問題,比如從屏幕觸摸輸入的,那就是顯示屏的input驅(qū)動(dòng);如果是藍(lán)牙外設(shè)輸入的,那就需要找BT的驅(qū)動(dòng)層。

adb shell getEvent

然后再輸入,看鍵值是否正常,如果getEvent都沒有收到,就不屬于framework的范疇了。

確定驅(qū)動(dòng)沒有問題之后,就可以通過動(dòng)態(tài)或靜態(tài)開啟debug log。不同廠商的開關(guān)log的命令有些差異,打印log的內(nèi)容也不太一樣。

這里我們直接以本地debug為例,參考Android T版本的common code自己添加關(guān)鍵log,然后開始復(fù)現(xiàn)問題,檢查問題時(shí)間點(diǎn)的log。順便補(bǔ)充一下,可以通過如下命令使時(shí)間顯示到秒,這樣方便復(fù)現(xiàn)問題時(shí)對(duì)應(yīng)log時(shí)間

adb shell settings put secure clock_seconds 1

Step1.查看ViewRootImpl是否有收到input event

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

      @UnsupportedAppUsage
      void enqueueInputEvent(InputEvent event,
              InputEventReceiver receiver, int flags, boolean processImmediately) {
          QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
          if (event instanceof MotionEvent) {
              MotionEvent me = (MotionEvent) event;
              if (me.getAction() == MotionEvent.ACTION_CANCEL) {
                  EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel",
                          getTitle().toString());
              }
          } else if (event instanceof KeyEvent) {
              KeyEvent ke = (KeyEvent) event;
              if (ke.isCanceled()) {
                  EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Key - Cancel",
                          getTitle().toString());
              }
          }
          // Always enqueue the input event in order, regardless of its time stamp.
          // We do this because the application or the IME may inject key events
          // in response to touch events and we want to ensure that the injected keys
          // are processed in the order they were received and we cannot trust that
          // the time stamp of injected events are monotonic.
          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);
          //添加log打印關(guān)鍵信息
          Log.i(">_<!!","enqueueInputEvent: event = " + event + " ,this = " + this);
          if (processImmediately) {
              doProcessInputEvents();
          } else {
              scheduleProcessInputEvents();
          }
      }

這里只需要根據(jù)添加的log查看兩個(gè)參數(shù)即可,event會(huì)打印出來 KeyEvent的action和keyCode,我們需要看下這里的action和keyCode是否有紊亂的情況,如果輸入和get到的不對(duì)應(yīng),那還是需要driver來協(xié)調(diào)。后面打印出來的this就是此ViewRootImpl對(duì)象,具體內(nèi)容可以看它的toString方法。

我們只需要在最終的log中觀察這句是否打印出來,如果打印出來了,說明input事件已經(jīng)成功發(fā)送到應(yīng)用端了,跳過下面步驟,直接檢查Step5,如果沒打印這段log,再看Step2

Step2. 查看inputDispatcher是否有收到input event

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

  bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
                                          DropReason* dropReason, nsecs_t* nextWakeupTime) {
      // Preprocessing.
      if (!entry->dispatchInProgress) {
          // 這個(gè)是AOSP的log機(jī)制,不用再另外添加log
          logOutboundKeyDetails("dispatchKey - ", *entry);
      }
  void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry& entry) {
      //if (DEBUG_OUTBOUND_EVENT_DETAILS) {
        if (true) {
          ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
                "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
                "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
                prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId,
                entry.policyFlags, entry.action, entry.flags, entry.keyCode, entry.scanCode,
                entry.metaState, entry.repeatCount, entry.downTime);
      }
  }

這里AOSP的log已經(jīng)添加的很全面了,我們只需要手動(dòng)將打印條件置為true即可。這段log中同樣可以對(duì)應(yīng)上action和keyCode,不過c++代碼打印出來的是十六進(jìn)制,但是也和上面java code中打印出來的字符串是一一對(duì)應(yīng)的。如果我們最終可以搜索到這段log,說明inputDispatcher已經(jīng)收到input event了,那么直接快進(jìn)到Step4檢查inputDispatcher狀態(tài)是否正常。如果沒有查看到這句log,再看Step3

Step3. 查看inputreader線程里面是否有keycode

/frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp

                                       int32_t usageCode) {
      int32_t keyCode;
      int32_t keyMetaState;
      uint32_t policyFlags;
      if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
                                    &policyFlags)) {
          keyCode = AKEYCODE_UNKNOWN;
          keyMetaState = mMetaState;
          policyFlags = 0;
      }
      if (mParameters.handlesKeyRepeat) {
          policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
      }
      NotifyKeyArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
                         getDisplayId(), policyFlags,
                         down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
                         AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
      getListener().notifyKey(&args);
      ALOGI("device: %s, keyCode=%d, scanCode=%d, eventTime = %lld, action=0x%x,duwnTime=%lld",getDeviceName().c_str(), keyCode, scanCode, args,eventTime, args.action. args.downTime);
  }

KeyboardInputMapper.cpp 是在Android R之后添加的工具,如果是比較舊的版本,需要在InputReader.cpp中添加log。此處可以確定input event被發(fā)送到了inputReader了,這里的值就是從getEvent讀取的,如果getEvent的值是對(duì)的,但這里沒有打印log,就需要打印cpp文件的callstack,看看是流程中哪一步出錯(cuò)。

Step4. 檢查inputDispatcher的狀態(tài)是否正常

可以通過adb命令來查看inputDispatcher的狀態(tài)

adb shell dumpsys input

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

  void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
      dump += StringPrintf(INDENT "DispatchEnabled: %s\n", toString(mDispatchEnabled));
      dump += StringPrintf(INDENT "DispatchFrozen: %s\n", toString(mDispatchFrozen));
      dump += StringPrintf(INDENT "InputFilterEnabled: %s\n", toString(mInputFilterEnabled));
      dump += StringPrintf(INDENT "FocusedDisplayId: %" PRId32 "\n", mFocusedDisplayId);

DispatcherEnabled 必須為1,并且DispatcherFrozen 必須為0,如果是inputDispatcher狀態(tài)有問題,需要在代碼中查看哪些地方有修改inputDispatcher的狀態(tài)mDispatchEnabled,mDispatchFrozen,找到將修改狀態(tài)的地方來分析問題。如果打印出來的FocusedDisplayId或FocusedApplications不符合預(yù)期,那就是display or WMS相關(guān)問題,與input流程沒有關(guān)系。

Step5. 查看最終input消費(fèi)event的是哪個(gè)頁面

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

      public boolean dispatchKeyEvent(KeyEvent event) {
          if (mInputEventConsistencyVerifier != null) {
              mInputEventConsistencyVerifier.onKeyEvent(event, 0);
          }
     Log.i(">_<!!","dispatchKeyEvent event:" + event + " to :" + v);
          // Give any attached key listener a first crack at the event.
          //noinspection SimplifiableIfStatement
          ListenerInfo li = mListenerInfo;
          if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
                  && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
              //表明input被消費(fèi)了
              Log.i(">_<!!","Event:" + event+ " handle in: " + v 
                  + " ,ListenerInfo = " + li.toString());
              return true;
          }
          if (event.dispatch(this, mAttachInfo != null
                  ? mAttachInfo.mKeyDispatchState : null, this)) {
              return true;
          }
          if (mInputEventConsistencyVerifier != null) {
              mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
          }
          return false;
      }

這里的log可以表明input event正在按照view的層級(jí)依次dispatch并最終被哪個(gè)view消費(fèi),如果這個(gè)view并不是所期望的view,那么就需要查看為什么消費(fèi)到這個(gè)view上面了,是layout區(qū)域有透明邊界?還是期望的view并不存在,可能性就很多,細(xì)節(jié)可以再深思下。如果這里的view是符合期望的,那么問題就回到應(yīng)用層了,看應(yīng)用層對(duì)此input事件的響應(yīng)是否有異常。

以上就是Android開發(fā)input問題解決分析的詳細(xì)內(nèi)容,更多關(guān)于Android input問題解決的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android開發(fā)新手常見的10個(gè)誤區(qū)

    Android開發(fā)新手常見的10個(gè)誤區(qū)

    這篇文章主要介紹了Android開發(fā)新手常見的10個(gè)誤區(qū),我們?nèi)匀豢吹搅四男┬碌腁ndr&#8203;&#8203;oid開發(fā)人員不斷重復(fù)的錯(cuò)誤,這里有10個(gè)最常見的誤區(qū),需要的朋友可以參考下
    2015-03-03
  • Android編程實(shí)現(xiàn)自定義漸變顏色效果詳解

    Android編程實(shí)現(xiàn)自定義漸變顏色效果詳解

    這篇文章主要介紹了Android編程實(shí)現(xiàn)自定義漸變顏色效果,結(jié)合具體實(shí)例形式分析了Android基于xml及代碼定義來實(shí)現(xiàn)顏色漸變的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2017-08-08
  • Android Support Library 標(biāo)題欄(Toolbar)滾動(dòng)效果實(shí)現(xiàn)方法

    Android Support Library 標(biāo)題欄(Toolbar)滾動(dòng)效果實(shí)現(xiàn)方法

    下面小編就為大家?guī)硪黄狝ndroid Support Library 標(biāo)題欄(Toolbar)滾動(dòng)效果實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-03-03
  • Kotlin創(chuàng)建一個(gè)好用的協(xié)程作用域

    Kotlin創(chuàng)建一個(gè)好用的協(xié)程作用域

    這篇文章主要介紹了Kotlin創(chuàng)建一個(gè)好用的協(xié)程作用域,kotlin中使用協(xié)程,是一定要跟協(xié)程作用域一起配合使用的,否則可能協(xié)程的生命周期無法被準(zhǔn)確控制,造成內(nèi)存泄漏或其他問題
    2022-07-07
  • Android NDK開發(fā)簡(jiǎn)單程序分享(Hello Word!)

    Android NDK開發(fā)簡(jiǎn)單程序分享(Hello Word!)

    本文主要對(duì)Android NDK開發(fā)簡(jiǎn)單程序(Hello Word!)的實(shí)現(xiàn)步驟及方法進(jìn)行詳細(xì)介紹。具有很好的參考價(jià)值,需要的朋友一起來看下吧
    2016-12-12
  • Android橫豎屏切換實(shí)例總結(jié)

    Android橫豎屏切換實(shí)例總結(jié)

    這篇文章主要介紹了Android橫豎屏切換的相關(guān)技巧,結(jié)合實(shí)例形式總結(jié)分析了Android禁止及設(shè)置橫豎屏切換、修改切換布局及攔截切換等相關(guān)技巧,需要的朋友可以參考下
    2016-01-01
  • Android使用自定義屬性實(shí)現(xiàn)圖片自動(dòng)播放滾動(dòng)的功能

    Android使用自定義屬性實(shí)現(xiàn)圖片自動(dòng)播放滾動(dòng)的功能

    這篇文章主要介紹了Android使用自定義屬性實(shí)現(xiàn)圖片自動(dòng)播放滾動(dòng)的功能,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • Android內(nèi)置的OkHttp用法介紹

    Android內(nèi)置的OkHttp用法介紹

    okhttp是一個(gè)第三方類庫,用于android中請(qǐng)求網(wǎng)絡(luò)。這是一個(gè)開源項(xiàng)目,是安卓端最火熱的輕量級(jí)框架,由移動(dòng)支付Square公司貢獻(xiàn)(該公司還貢獻(xiàn)了Picasso和LeakCanary) 。用于替代HttpUrlConnection和Apache HttpClient
    2022-08-08
  • Android自定義帶有圓形進(jìn)度條的可長(zhǎng)按控件功能

    Android自定義帶有圓形進(jìn)度條的可長(zhǎng)按控件功能

    這篇文章主要介紹了Android自定義帶有圓形進(jìn)度條的可長(zhǎng)按控件,思路很簡(jiǎn)單,使用簡(jiǎn)單的畫筆工具就可以完成這個(gè)控件,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2022-06-06
  • 如何在android中制作一個(gè)方向輪盤詳解

    如何在android中制作一個(gè)方向輪盤詳解

    這篇文章主要給大家介紹了關(guān)于如何在android中制作一個(gè)方向輪盤的相關(guān)資料,這個(gè)是在手游領(lǐng)域中很常見的用于控制方向的輪盤,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09

最新評(píng)論

右玉县| 无棣县| 社旗县| 德令哈市| 黑河市| 广安市| 太湖县| 秀山| 辉县市| 厦门市| 永平县| 大宁县| 鄱阳县| 汉川市| 荔波县| 武威市| 太原市| 永嘉县| 山东| 綦江县| 青川县| 开平市| 商水县| 黄浦区| 厦门市| 昭苏县| 尼勒克县| 丹巴县| 钟祥市| 阿坝| 延川县| 郓城县| 安吉县| 富平县| 苏尼特左旗| 屏山县| 平遥县| 厦门市| 炎陵县| 鹤庆县| 景泰县|