InputManagerService inputDispatcher of important Android Framework services

The InputDispatcher thread is used to obtain and distribute events from the mInboundQueue queue. This chapter introduces the relevant knowledge of InputDispatcher.


After the InputDispatcherThread thread is started, a thredLoop method will also be called. This method obtains events from the mInboundQueue queue and performs subsequent processing. The relevant code is located in frameworks/native/services/inputlinker/dispatcher/inputdispatcher cpp:

status_t InputDispatcher::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    mThread = std::make_unique<InputThread>(
            "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
    return OK;

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        // Wake up the waiting thread. monitor() is used to monitor whether the dispatcher has a deadlock
        // When an event is generated in the mInboundQueue, obtain the lock and handle the related event
        if (!haveCommandsLocked()) {
    } // release lock
     //After inputReader reads the event and puts the event into the minBoundQueue, it calls loop::wake to wake up the inputDispatcher
bool InputDispatcher::haveCommandsLocked() const {
    return !mCommandQueue.isEmpty();

The thread executes looper->pollonce and enters epoll_wait status: exit the wait status when any of the following occurs:

  • Callback: wake up through callback method;
  • Timeout: when nextWakeupTime is reached, wake up after timeout;
  • Wake: actively call the wake() method of Looper;

1.1 dispatchOnceInnerLocked

dispatchOnceInnerLocked will take EntryEvent from the mInboundQueue queue header and assign it to mPendingEvent. It will be processed differently according to the type of input event. After the processing is completed, the mPendingEvent will be released. The relevant code is located in frameworks/native/services/inputlinker/dispatcher/ inputdispatcher cpp:

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    // Get current time
    nsecs_t currentTime = now();
    // Optimize the app handover delay. When the handover times out, preempt the distribution and discard all other events to be processed.
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    if (mAppSwitchDueTime < *nextWakeupTime) {
        *nextWakeupTime = mAppSwitchDueTime;

    // mPendingEvent initialized to null
    if (!mPendingEvent) {
        if (mInboundQueue.empty()) {
            if (isAppSwitchDue) {
                // The inbound queue is empty so the app switch key we were waiting
                // for will never arrive.  Stop waiting for it.
                isAppSwitchDue = false;
            if (!mPendingEvent) {
                // If the mInboundQueue queue is empty, it will be returned directly when there are no events to process
        } else {
            // Events for fetching headers from mInboundQueue
            mPendingEvent = mInboundQueue.front();
    // Event distribution
    switch (mPendingEvent->type) {
        // Distribution configuration change event
        case EventEntry::Type::CONFIGURATION_CHANGED: {

        // Distribution input device reset event
        case EventEntry::Type::DEVICE_RESET: {

        // Distribute focus events
        case EventEntry::Type::FOCUS: {

        // Touch point change event when distributing multi touch
        case EventEntry::Type::POINTER_CAPTURE_CHANGED: {

        // Distribute drag and drop events
        case EventEntry::Type::DRAG: {

        // Distribute key events
        case EventEntry::Type::KEY: {

        // Distribute touch events
        case EventEntry::Type::MOTION: {
            // Force mPendingEvent to MotionEntry
            std::shared_ptr<MotionEntry> motionEntry =
            if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
                dropReason = DropReason::APP_SWITCH;
            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
                dropReason = DropReason::STALE;
            if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
                dropReason = DropReason::BLOCKED;
            // If it is a Motion Event, the dispatchMotionLocked branch will be taken
            done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
        // Distribute sensor events
        case EventEntry::Type::SENSOR: {

    if (done) {
        if (dropReason != DropReason::NOT_DROPPED) {
            dropInboundEventLocked(*mPendingEvent, dropReason);
        mLastDropReason = dropReason;

        // Release mPendingEvent after processing
        *nextWakeupTime = LONG_LONG_MIN;

As can be seen from the above code, when inputDispatcher obtains an event, it will be distributed according to the event type. At present, the following events will be distributed:

  • Configuration change event [evententry:: type:: configuration\u changed]
  • Input device reset event [evententry:: type:: device\u reset]
  • Focus event [EventEntry::Type::FOCUS]
  • Touch point change event [evententry:: type:: pointer\u capture\u changed]
  • Drag event [EventEntry::Type::DRAG]
  • Key event [EventEntry::Type::KEY]
  • Touch event [EventEntry::Type::MOTION]
  • Sensor event [EventEntry::Type::SENSOR]

The following takes the MotionEvent event as an example to analyze the processing flow of the input event.

1.2 dispatchMotionLocked

dispatchMotionLocked is used to handle touch events. The relevant code is located in frameworks/native/services/inputlinker/dispatcher/inputdispatcher cpp:

bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,
                                           DropReason* dropReason, nsecs_t* nextWakeupTime) {

    // Determine whether it is a Touch event
    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

    // Identify targets.
    std::vector<InputTarget> inputTargets;

    bool conflictingPointerActions = false;
    InputEventInjectionResult injectionResult;
    if (isPointerEvent) {
        // Find the focus window for Touch events
        injectionResult =
                findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,
    } else {
        // Find focus window for non Touch events
        injectionResult =
                findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);

    // For MotionEvent, input is returned in four cases_ EVENT_ INJECTION_ Pending status
    // There are two cases when the focus window is empty and the focus application is not empty:
    // 1. the timeout for missing focus window is not set;
    // 2. the time-out period of the focus window has not expired;
    // 3. when the focus window and focus application are not empty:
    // 4. the focus window is suspended;
    if (injectionResult == InputEventInjectionResult::PENDING) {
        return false;

    // Start distributing events after the target window is found
    if (conflictingPointerActions) {
        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                                   "conflicting pointer actions");
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;

For Touch events and non Touch events, there are two different logics to find focus windows: findTouchedWindowTargetsLocked has a lot of processing logics about split screen and multiple display IDs. Compared with findFocusedWindowTargetsLocked, the code logic is slightly more complex. In order to focus on the main process of event distribution, we take findFocusedWindowTargetsLocked as an example to illustrate the process of finding focus windows;

1.3 findFocusedWindowTargetsLocked

findFocusedWindowTargetsLocked is used to find the focus window. The relevant code is located in frameworks/native/services/inputlinker/dispatcher/inputdispatcher cpp:

int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
                                                        const EventEntry& entry,
                                                        std::vector<InputTarget>& inputTargets,
                                                        nsecs_t* nextWakeupTime) {
    std::string reason;
    // Find the display id of the input event. Since Android supports multi screen devices, there may be multiple display IDs. The default is 0
    int32_t displayId = getTargetDisplayId(entry);
    // Find InputWindowHandle based on display id
    std::shared_ptr<InputApplicationHandle> focusedApplicationHandle =
        getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
    // Find InputApplicationHandle based on display id
    sp<InputApplicationHandle> focusedApplicationHandle =
            getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);

    // If focusedwindownhandle and focusedApplicationHandle are both empty, it means that there is no focus application or focus window at present, so this event will be discarded directly
    if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) {
        ALOGI("Dropping %s event because there is no focused window or focused application in "
              "display %" PRId32 ".",
              EventEntry::typeToString(entry.type), displayId);
    // The focus application is not empty and the focus window is empty
    if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) {
        // Timeout for missing focus window is not set
        if (!mNoFocusedWindowTimeoutTime.has_value()) {
            // We just discovered that there's no focused window. Start the ANR timer
            // Obtain the timeout, which is 5s by default
            const nsecs_t timeout = focusedApplicationHandle->getDispatchingTimeout(
            // Record timeout
            mNoFocusedWindowTimeoutTime = currentTime + timeout;
            // Record focus application waiting for focus window
            mAwaitedFocusedApplication = focusedApplicationHandle;
            ALOGW("Waiting because no window has focus but %s may eventually add a "
                  "window when it finishes starting up. Will wait for %" PRId64 "ms",
                  mAwaitedFocusedApplication->getName().c_str(), ns2ms(timeout));
            *nextWakeupTime = *mNoFocusedWindowTimeoutTime;
        } else if (currentTime > *mNoFocusedWindowTimeoutTime) {
            // If it has timed out, the event will be discarded directly
            ALOGE("Dropping %s event because there is no focused window",
        } else {
            // Wait until the timeout period expires

    // Reset timeout and waiting focus application

    // Check permissions.
    if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {

    // The focus window has been paused
    if (focusedWindowHandle->getInfo()->paused) {
        ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());

    // After successfully finding the focus window, add it to inputTargets
                          InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
                          BitSet32(0), inputTargets);

    // Done.

There are two very important maps: mFocusedWindowHandlesByDisplay and mFocusedApplicationHandlesByDisplay. They store the focus application and focus window corresponding to each current display respectively. These maps are displayed in frameworks/native/services/inputlinker/dispatcher/ inputdispatcher H declared:

// key is display id, value is InputWindowHandle, i.e. focus window
std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay

// key is display id, value is InputApplicationHandle, i.e. focus application
std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay

1.4 setInputWindowsLocked

setInputWindowsLocked is used to set the focus window. The relevant code is located in frameworks/native/services/inputlinker/dispatcher/inputdispatcher cpp:

void InputDispatcher::setInputWindowsLocked(
        const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) {
    // Find all current inputwindowhandles from mwindownesbydisplay according to displayId, including focus windows and non focus windows
    const std::vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);

    sp<InputWindowHandle> newFocusedWindowHandle = nullptr;
    bool foundHoveredWindow = false;
    for (const sp<InputWindowHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
        // Set newFocusedWindowHandle to the top most focused window instead of the last one
        // Traverse the updated list of all windows, and set the window that is visible and gets the focus as the new focus window
        if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus &&
            windowHandle->getInfo()->visible) {
            newFocusedWindowHandle = windowHandle;
        if (windowHandle == mLastHoverWindowHandle) {
            foundHoveredWindow = true;

    if (!foundHoveredWindow) {
        mLastHoverWindowHandle = nullptr;

    // Find the current focus window from mFocusedWindowHandlesByDisplay according to displayId
    sp<InputWindowHandle> oldFocusedWindowHandle =
            getValueByKey(mFocusedWindowHandlesByDisplay, displayId);

    // Different inputwindowhandles have different token s
    if (!haveSameToken(oldFocusedWindowHandle, newFocusedWindowHandle)) {
        if (oldFocusedWindowHandle != nullptr) {
            if (DEBUG_FOCUS) {
                ALOGD("Focus left window: %s in display %" PRId32,
                      oldFocusedWindowHandle->getName().c_str(), displayId);
            // Get the corresponding InputChannel according to the Token in the InputWindowHandle
            sp<InputChannel> focusedInputChannel =
            if (focusedInputChannel != nullptr) {
                CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
                                           "focus left window");
                synthesizeCancelationEventsForInputChannelLocked(focusedInputChannel, options);
                // Add FocusEntry losing focus to mInboundQueue
                enqueueFocusEventLocked(*oldFocusedWindowHandle, false /*hasFocus*/);
            // Remove historical InputWindowHandle from mFocusedWindowHandlesByDisplay
        if (newFocusedWindowHandle != nullptr) {
            if (DEBUG_FOCUS) {
                ALOGD("Focus entered window: %s in display %" PRId32,
                      newFocusedWindowHandle->getName().c_str(), displayId);
            // Update mFocusedWindowHandlesByDisplay
            mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
            // Add FocusEntry to mInboundQueue to get focus
            enqueueFocusEventLocked(*newFocusedWindowHandle, true /*hasFocus*/);

        // Add a CommandEntry for focus change to the mCommandQueue to notify the upper level of focus window change
        if (mFocusedDisplayId == displayId) {
            onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);

Each display corresponds to several inputwindowhandles and a focus InputWindowHandle. This method will update mwindownhandlesbydisplay and mFocusedWindowHandlesByDisplay according to the incoming InputWindowHandle list. The calling process is as follows:


1.5 setFocusedApplication

setFocusedApplication is used to set the focus application. The relevant codes are located in frameworks/native/services/inputlinker/dispatcher/inputdispatcher cpp:

void InputDispatcher::setFocusedApplication(
        int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
    if (DEBUG_FOCUS) {
        ALOGD("setFocusedApplication displayId=%" PRId32 " %s", displayId,
              inputApplicationHandle ? inputApplicationHandle->getName().c_str() : "<nullptr>");
    { // acquire lock
        std::scoped_lock _l(mLock);
        // Set focus application
        setFocusedApplicationLocked(displayId, inputApplicationHandle);
    } // release lock

    // Wake up poll loop since it may need to make new input dispatching choices.

1.6 dispatchEventLocked

dispatchEventLocked is used to pass input events. The relevant codes are located in frameworks/native/services/inputlinker/dispatcher/inputdispatcher cpp:

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
                                          const std::vector<InputTarget>& inputTargets) {
    for (const InputTarget& inputTarget : inputTargets) {
        // Find the Connection corresponding to InputChannel
        sp<Connection> connection =
        if (connection != nullptr) {
            // If the Connection is not empty, start preparing to distribute input events
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);

The ispatchEventLocked function finds the corresponding Connection according to the InputTarget. It is the channel connecting the native application process. With it, you can start preparing to distribute input events.

1.7 prepareDispatchCycleLocked

The prepareDispatchCycleLocked function is used to prepare to distribute input events. In this function, the connection status will be verified. When the connection status is normal, the event will be queued. The relevant code is located in frameworks/native/services/inputlinker/dispatcher/inputdispatcher cpp:

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                                                 const sp<Connection>& connection,
                                                 EventEntry* eventEntry,
                                                 const InputTarget& inputTarget) {
    // If the Connection status is abnormal, the direct return will not add the input event to the mOutbound queue
    if (connection->status != Connection::STATUS_NORMAL) {

    // Queue input event
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);

1.8 enqueueDispatchEntriesLocked

enqueueDispatchEntriesLocked function is used to queue input events. The relevant codes are located in frameworks/native/services/inputlinker/dispatcher/inputdispatcher cpp:

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
                                                   const sp<Connection>& connection,
                                                   EventEntry* eventEntry,
                                                   const InputTarget& inputTarget) {
    // Determine whether the outboundQueue of the Connection is empty
    bool wasEmpty = connection->outboundQueue.empty();

    // Queue input event
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,

    // If the outbound queue was previously empty, start the dispatch cycle going.
    if (wasEmpty && !connection->outboundQueue.empty()) {
        // If the previous outboundQueue is empty, and it is not empty after enqueueDispatchEntryLocked, the event distribution starts
        startDispatchCycleLocked(currentTime, connection);

1.9 startDispatchCycleLocked

startDispatchCycleLocked is used to distribute input events. The relevant codes are located in frameworks/native/services/inputlinker/dispatcher/inputdispatcher cpp:

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
                                               const sp<Connection>& connection) {
    // After enqueueDispatchEntryLocked, connection->outboundqueue is not empty
    while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
        DispatchEntry* dispatchEntry = connection->outboundQueue.front();
        // Record the time of event distribution
        dispatchEntry->deliveryTime = currentTime;
        // The default timeout is 5s
        const nsecs_t timeout =
        // The distribution timeout is the current time plus the default timeout
        dispatchEntry->timeoutTime = currentTime + timeout;
        // Publish the event.
        status_t status;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        switch (eventEntry->type) {
            case EventEntry::Type::MOTION: {
                MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
                // Get event signature
                std::array<uint8_t, 32> hmac = getSignature(*motionEntry, *dispatchEntry);

                // Inputpublisher Publishmotionevent publishes the input event
                status = connection->inputPublisher
                                                     motionEntry->deviceId, motionEntry->source,
                                                     motionEntry->displayId, std::move(hmac),
                                                     motionEntry->edgeFlags, motionEntry->metaState,
                                                     motionEntry->classification, xScale, yScale,
                                                     xOffset, yOffset, motionEntry->xPrecision,
                                                     motionEntry->downTime, motionEntry->eventTime,
                                                     motionEntry->pointerProperties, usingCoords);

        // After publishing, remove the DispatchEntry from the outboundQueue of the Connection
        // Then add the DispatchEntry to the waitQueue of the Connection
        if (connection->responsive) {
            // Insert a record into AnrTracker

1.10 publishMotionEvent

The publishMotionEvent function publishes events. The relevant code is located in frameworks/native/libs/input/inputtransport cpp:

status_t InputPublisher::publishMotionEvent(
        uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, int32_t displayId,
        std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
        int32_t edgeFlags, int32_t metaState, int32_t buttonState,
        MotionClassification classification, float xScale, float yScale, float xOffset,
        float yOffset, float xPrecision, float yPrecision, float xCursorPosition,
        float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
        const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
    InputMessage msg;
    msg.header.type = InputMessage::Type::MOTION;
    msg.body.motion.seq = seq;
    msg.body.motion.eventId = eventId;
    msg.body.motion.deviceId = deviceId;
    msg.body.motion.source = source;
    msg.body.motion.displayId = displayId;
    msg.body.motion.hmac = std::move(hmac);
    msg.body.motion.action = action;
    msg.body.motion.actionButton = actionButton;
    msg.body.motion.flags = flags;
    msg.body.motion.edgeFlags = edgeFlags;
    msg.body.motion.metaState = metaState;
    msg.body.motion.buttonState = buttonState;
    msg.body.motion.classification = classification;
    msg.body.motion.xScale = xScale;
    msg.body.motion.yScale = yScale;
    msg.body.motion.xOffset = xOffset;
    msg.body.motion.yOffset = yOffset;
    msg.body.motion.xPrecision = xPrecision;
    msg.body.motion.yPrecision = yPrecision;
    msg.body.motion.xCursorPosition = xCursorPosition;
    msg.body.motion.yCursorPosition = yCursorPosition;
    msg.body.motion.downTime = downTime;
    msg.body.motion.eventTime = eventTime;
    msg.body.motion.pointerCount = pointerCount;
    for (uint32_t i = 0; i < pointerCount; i++) {
    // Encapsulate the input event into an InputMessage and continue through the inputchannel SendMessage send message
    return mChannel->sendMessage(&msg);

1.11 sendMessage

sendMessage sends events to the application process. The relevant codes are located in frameworks/native/libs/input/inputtransport cpp:

status_t InputChannel::sendMessage(const InputMessage* msg) {
    const size_t msgLength = msg->size();
    InputMessage cleanMsg;
    ssize_t nWrite;
    do {
        // Send InputMessage to application process through socket
        nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
    return OK;


So far, the work of inputdispatcher has come to an end. The events are finally sent to the client through the socket. The following is the overall flow chart of inputdispatcher for your reference:

end of document

If you want to be an architect, you should not be limited to coding and business. You should be able to select, expand and improve your programming thinking. In addition, good career planning is also very important. The habit of learning is very important, but the most important thing is to persevere. Any plan that cannot be implemented is empty talk.

If you have no direction, here is a set of advanced notes on the eight Android modules prepared by Ali senior architects to help you systematize the messy, scattered and fragmented knowledge, so that you can systematically and efficiently master all the knowledge points of Android development.

Compared with the fragmented content we usually read, the knowledge points of this note are more systematic, easier to understand and remember, and are arranged strictly according to the knowledge system.

1, Necessary skills for architects to build foundations

1. Deep understanding of Java generics
2. Notes in simple terms
3. Concurrent programming
4. Data transmission and serialization
5. Principles of Java virtual machine
6. High efficiency IO

2, Source code analysis of top 100 Android frameworks

1.retro 2.0 source code analysis
2.Okhttp3 source code analysis
3.ButterKnife source code analysis
4.mpadroidchart source code analysis
5.Glide source code analysis
6.Leakcanary source code analysis
7. Universal lmage loader source code analysis
8.EventBus 3.0 source code analysis
9.zxing source code analysis
10.Picasso source code analysis
11.LottieAndroid usage details and source code analysis
12.Fresco source code analysis - picture loading process

3, Practical analysis of Android performance optimization

  • Tencent Bugly: some understanding of string matching algorithm
  • Iqiyi: Android APP crash capture scheme - xCrash
  • Byte skipping: deeply understand one of the Gradle frameworks: Plugin, Extension, buildSrc
  • Baidu APP Technology: Android H5 first screen Optimization Practice
  • Alipay client architecture analysis: Android client startup speed optimization "garbage collection"
  • Ctrip: component architecture practice from the perspective of Zhixing Android project
  • Netease News Construction Optimization: how to make your construction speed "like lightning"?
  • ...

4, Advanced kotlin enhanced combat

1. Getting started with Kotlin
2. Kotlin practical pit avoidance Guide
3. Project practice "Kotlin Jetpack practice"

  • Start with a Demo of worshiping the great God

  • What was Kotlin's experience writing Gradle scripts?

  • Three realms of Kotlin programming

  • Kotlin higher order function

  • Kotlin generics

  • Kotlin extension

  • Entrusted by Kotlin

  • Debugging skills of "unknown" coordination process

  • Graphic collaboration: suspend

5, Advanced decryption of Android advanced UI open source framework

1. Use of smartrefreshlayout
2.Android PullToRefresh control source code analysis
3. Basic usage of Android pulltorefresh pull-down refresh Library
4.LoadSir- efficient and easy-to-use loading feedback page management framework
5. Detailed explanation of Android general LoadingView loading framework
6.mpadroidchart implements LineChart (line chart)
7. Hellocharts Android User Guide
8.SmartTable User Guide
9. introduction to the open source project Android uitableview
10.ExcelPanel User Guide
11. Deep analysis of Android open source project SlidingMenu
12.MaterialDrawer User Guide

6, NDK module development

1. NDK module development
2. JNI module
3. Native development tools
4. Linux Programming
5. Bottom picture processing
6. Audio and video development
7. Machine learning

7, Advanced shuttle Technology

1. Overview of Flutter cross platform development
2. Setup of the fluent development environment in Windows
3. Write your first shuttle app
4. Setup and debugging of Flutter development environment
5. Basic grammar of Dart Grammar (1)
6. The use and source code analysis of the collection of Dart Grammar (2)
7. Set operator functions and source code analysis in Dart Grammar (3)

8, Wechat applet development

1. Applet overview and introduction
2. Applet UI development
3. API operation
4. Shopping mall project practice

Full set of video materials:

1, Interview collection

2, Source code analysis collection

3, Open source framework collection

You are welcome to support three links with one button. If you need the information in the text, you can directly click on the official certified wechat card of CSDN at the end of the text to receive [guarantee 100% free] ↓↓

Tags: Android Framework

Posted by posidon on Thu, 02 Jun 2022 23:12:20 +0530