91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Andriod事件分發事件怎么來的

發布時間:2023-03-15 14:17:10 來源:億速云 閱讀:109 作者:iii 欄目:開發技術

本篇內容主要講解“Andriod事件分發事件怎么來的”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Andriod事件分發事件怎么來的”吧!

Android事件分發的事件從何而來

事件分發一直以來都是一個android知識的重點。從應用開發角度和用戶的交互就是在處理事件。

Activity的事件分發

事件分發一般情況都會講view的分發過程,他的過程縮略起來就可以這樣表示。

public boolean diapatchTouchEvent(MotionEvent ev) {
    boolean consume = false;
    if (onInterceptTouchEvent(ev)) {
        consume = onTouchEvent(ev);
    } else {
        consume = child.dispatchTouchEvent(ev);
    }
    return consume;
}

這里就有一個問題,最早的事件是從哪里來的。根據Android的視圖模型知道最外層的view就是DecorView ,而它的外面是一個PhoneWindow。所以最初的事件就是從PhoneWindow進入了view的事件分發,而PhoneWindow的事件又是Activity中來的.

//frameworks/base/core/java/android/app/Activity.java
public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {//這里獲取的PhoneWindow
            return true;
        }
        return onTouchEvent(ev);
    }

那么問題又來了,activity的事件是哪里來的呢。

ViewRootImpl事件分發

熟悉Android的Window創建流程的話就知道ViewRootImpl是所有view的最頂層。也是ViewRootImpl在setView中實現了View和WindowManager之間的交互。這個方法里有一個在Window創建流程的時候沒有關注的InputChannel,事件真正的來源就是它,在

 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
              .........
                InputChannel inputChannel = null;//創建InputChannel
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    inputChannel = new InputChannel();
                }
              
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,mTempControls, attachedFrame, sizeCompatScale);//將InputChannel傳給WMS
                if (inputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                            Looper.myLooper());//創建mInputEventReceiver
                }
              //這里創建了各種事件處理器
                // Set up the input pipeline.
                CharSequence counterSuffix = attrs.getTitle();
                mSyntheticInputStage = new SyntheticInputStage();
                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
                InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
                InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
                InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);
                mFirstInputStage = nativePreImeStage;
                mFirstPostImeInputStage = earlyPostImeStage;
                mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
                AnimationHandler.requestAnimatorsEnabled(mAppVisible, this);
            }
        }
    }

從名字也能猜出mInputEventReceiver就是接收事件的對象了,這是一個ViewRootImpl的內部類看下它的實現。

 final class WindowInputEventReceiver extends InputEventReceiver {
        public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }
        @Override
        public void onInputEvent(InputEvent event) {//通過名字就知道這應該是事件接收的回調
            List<InputEvent> processedEvents;
            try {
                processedEvents =
                    mInputCompatProcessor.processInputEventForCompatibility(event);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
            if (processedEvents != null) {
                if (processedEvents.isEmpty()) {
                    // InputEvent consumed by mInputCompatProcessor
                    finishInputEvent(event, true);
                } else {
                    for (int i = 0; i < processedEvents.size(); i++) {
                        enqueueInputEvent(
                                processedEvents.get(i), this,
                                QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
                    }
                }
            } else {
                enqueueInputEvent(event, this, 0, true);
            }
        }
   .......
 }

如果processedEvents不為空都是調用了enqueueInputEvent,不然就直接調用finishInputEvent。

 void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
        //這里做了區分是觸摸事件還是按鍵事件
        if (event instanceof MotionEvent) {
            MotionEvent me = (MotionEvent) event;
        } else if (event instanceof KeyEvent) {
            KeyEvent ke = (KeyEvent) event;
        }
       
        QueuedInputEvent last = mPendingInputEventTail;
        if (last == null) {
            mPendingInputEventHead = q;
            mPendingInputEventTail = q;
        } else {
            last.mNext = q;
            mPendingInputEventTail = q;
        }
        mPendingInputEventCount += 1;
        if (processImmediately) {
            doProcessInputEvents();
        } else {
            scheduleProcessInputEvents();
        }
    }
    private void scheduleProcessInputEvents() {
        if (!mProcessInputEventsScheduled) {
            mProcessInputEventsScheduled = true;
            Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
            msg.setAsynchronous(true);
            mHandler.sendMessage(msg);
        }
    }
  private void handleMessageImpl(Message msg) {
            switch (msg.what) {
               case MSG_PROCESS_INPUT_EVENTS:
                    mProcessInputEventsScheduled = false;
                    doProcessInputEvents();
            }
  }

這里判斷了是否要立即消費,如果立即消費doProcessInputEvents,不然調用scheduleProcessInputEvents。而scheduleProcessInputEvents很簡單就是handle發送了一個異步消息。最后handle執行的時候還是會調用到doProcessInputEvents。所以就來詳細看下doProcessInputEvents。

    void doProcessInputEvents() {
        // Deliver all pending input events in the queue.
        while (mPendingInputEventHead != null) {//循環獲取InputEvent并處理
            QueuedInputEvent q = mPendingInputEventHead;
            mPendingInputEventHead = q.mNext;
            if (mPendingInputEventHead == null) {
                mPendingInputEventTail = null;
            }
            q.mNext = null;
            mPendingInputEventCount -= 1;
            mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
            deliverInputEvent(q);
        }
        //移除異步消息
        if (mProcessInputEventsScheduled) {
            mProcessInputEventsScheduled = false;
            mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
        }
    }

可以看到真實的處理都是deliverInputEvent來處理。

 private void deliverInputEvent(QueuedInputEvent q) {
        try {
            if (mInputEventConsistencyVerifier != null) {
            InputStage stage;//在ViewRootImpl的setView中初始化的處理器
            if (q.shouldSendToSynthesizer()) {
                stage = mSyntheticInputStage;
            } else {
                stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
            }
            if (q.mEvent instanceof KeyEvent) {
                try {
                    mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
            }
            if (stage != null) {
                handleWindowFocusChanged();
                stage.deliver(q);
            } else {
                finishInputEvent(q);
            }
        } finally {
        }
    }

在deliverInputEvent中出現了stage,這就是在setView初始化的那些處理器,處理通過stage.deliver(q)來實現。 InputStage 還是ViewRootImpl的一個內部類。

 abstract class InputStage {
        private final InputStage mNext;
        protected static final int FORWARD = 0;
        protected static final int FINISH_HANDLED = 1;
        protected static final int FINISH_NOT_HANDLED = 2;
        private String mTracePrefix;
        public InputStage(InputStage next) {
            mNext = next;
        }
        public final void deliver(QueuedInputEvent q) {
          //分發事件
            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
                forward(q);
            } else if (shouldDropInputEvent(q)) {
                finish(q, false);
            } else {
                traceEvent(q, Trace.TRACE_TAG_VIEW);
                final int result;
                try {
                    result = onProcess(q);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
                apply(q, result);
            }
        }
        //處理事件由子類改寫
        protected int onProcess(QueuedInputEvent q) {
            return FORWARD;
        }
        protected void finish(QueuedInputEvent q, boolean handled) {
            q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
            if (handled) {
                q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
            }
            forward(q);
        }
        protected void forward(QueuedInputEvent q) {
            onDeliverToNext(q);
        }
        protected void onDeliverToNext(QueuedInputEvent q) {
          //向后一個 InputStage 傳遞事件
            if (mNext != null) {
                mNext.deliver(q);
            } else {
                finishInputEvent(q);
            }
        }
    }

熟悉okhttp的話很容易就發現這里也是一個責任鏈模式。從setView中 InputStage 子類的初始化也能看到,其中和view相關的是ViewPostImeInputStage。

 final class ViewPostImeInputStage extends InputStage {
        public ViewPostImeInputStage(InputStage next) {
            super(next);
        }
        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                return processKeyEvent(q);
            } else {
                final int source = q.mEvent.getSource();
              //判斷事件類型,觸摸事件會進入processPointerEvent
                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                    return processPointerEvent(q);
                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                    return processTrackballEvent(q);
                } else {
                    return processGenericMotionEvent(q);
                }
            }
        }
        private int processPointerEvent(QueuedInputEvent q) {
            final MotionEvent event = (MotionEvent)q.mEvent;
            mHandwritingInitiator.onTouchEvent(event);
            mAttachInfo.mUnbufferedDispatchRequested = false;
            mAttachInfo.mHandlingPointerEvent = true;
          //通過mView的dispatchPointerEvent來分發事件
            boolean handled = mView.dispatchPointerEvent(event);
            maybeUpdatePointerIcon(event);
            maybeUpdateTooltip(event);
            mAttachInfo.mHandlingPointerEvent = false;
            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
                mUnbufferedInputDispatch = true;
                if (mConsumeBatchedInputScheduled) {
                    scheduleConsumeBatchedInputImmediately();
                }
            }
            return handled ? FINISH_HANDLED : FORWARD;
        }

ViewRootImpl的事件就交給mView來繼續分發了,這里mView是DecorView,也是在setView中傳進來的。

DecorView事件處理

  //frameworks/base/core/java/android/view/View.java
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            return dispatchTouchEvent(event);
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }
//frameworks/base/core/java/com/android/internal/policy/DecorView.java
 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final Window.Callback cb = mWindow.getCallback();
        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
    }

這里通過dispatchTouchEvent將事件交給了Window.Callback,而這里的Window.Callback就是Activity,兜兜轉轉終于回到了Activity的dispatchTouchEvent中。

通過這個流程可以知道,事件的流程是WMS->ViewRootImpl->DecorView->Activity->PhoneWindow->DecorView,這里有一個疑問就是為什么不直接從DecorView開始分發。我猜測是為了方便在應用層重寫Activity中的onTouch來消費沒有view處理的事件。

到此,相信大家對“Andriod事件分發事件怎么來的”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

二连浩特市| 三亚市| 乐安县| 合江县| 康马县| 红原县| 鄂托克旗| 霍城县| 威远县| 祁东县| 临猗县| 米易县| 临汾市| 建始县| 麦盖提县| 莆田市| 扶风县| 阳泉市| 江北区| 皋兰县| 同江市| 阳西县| 镇远县| 凯里市| 西充县| 阳新县| 自治县| 潜江市| 淅川县| 海宁市| 泗洪县| 桂东县| 无为县| 晋城| 沙坪坝区| 手游| 东兰县| 庄河市| 昭平县| 泽州县| 福安市|