亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

EventBus源碼分析

Tecode / 1248人閱讀

摘要:第二種是通過(guò)方法來(lái)檢查,源碼如下通過(guò)以及來(lái)生成一個(gè),來(lái)存儲(chǔ)方法所在的類。先看下的方法繼承了,調(diào)用方法后會(huì)向事件隊(duì)列中插入一個(gè)事件,然后將標(biāo)記位設(shè)置為表示正在處理事件,然后調(diào)用發(fā)送消息通知處理事件。

首先從訂閱開(kāi)始

EventBus.getDefault().register(this);

register方法會(huì)獲取傳入的object對(duì)象的class,通過(guò)findSubscriberMethods方法來(lái)查找這個(gè)class中訂閱的方法,如下

    public void register(Object subscriber) {
        Class<");synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

findSubscriberMethods方法實(shí)現(xiàn)如下,其中有一個(gè)ConcurrentHashMap類型的靜態(tài)對(duì)象METHOD_CACHE,是用來(lái)緩存對(duì)應(yīng)類的訂閱方法的,以便后續(xù)再次訂閱時(shí)不用重新去findMethods,可以直接從緩存中讀取。

    List findSubscriberMethods(Class<"); {
        List subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        if (subscriberMethods.isEmpty()) {
            throw new EventBusException("Subscriber " + subscriberClass
                    + " and its super classes have no public methods with the @Subscribe annotation");
        } else {
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

查找訂閱方法通過(guò)ignoreGeneratedIndex字段分為兩種方式

第一種findUsingReflection是通過(guò)反射來(lái)查找,找到被@Subscribe注解修飾的方法,并且根據(jù)具體的注解以及方法參數(shù)生成一個(gè)SubscriberMethod對(duì)象:

findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));

第二種findUsingInfo是通過(guò)apt的方式,提前找到訂閱的方法,可以避免通過(guò)反射查找方法帶來(lái)的耗時(shí)。

具體使用方法:在gradle配置apt,rebuild項(xiàng)目,會(huì)生成一個(gè)注解方法索引類,在EventBusBuilder中通過(guò)addIndex方法新建一個(gè)該類的對(duì)象傳入即可。

這邊還有一個(gè)問(wèn)題,對(duì)于子類重寫(xiě)父類的訂閱方法如何處理。在上面的兩種方式中在查找完子類的訂閱方法后都會(huì)繼續(xù)去查找父類的訂閱方法,都通過(guò)一個(gè)叫做checkAdd的方法進(jìn)行支撐,該方法返回true表示可以添加到訂閱方法的集合中去。

boolean checkAdd(Method method, Class<"); {
    // 2 level check: 1st level with event type only (fast), 2ndlevelwith complete signature when required.
    // Usually a subscriber doesn"t have methods listening to thesameevent type.
    Object existing = anyMethodByEventType.put(eventType, method);
    if (existing == null) {
        return true;
    } else {
        if (existing instanceof Method) {
            if (!checkAddWithMethodSignature((Method)existing,eventType)) {
                // Paranoia check
                throw new IllegalStateException();
            }
            // Put any non-Method object to "consume" theexistingMethod
            anyMethodByEventType.put(eventType, this);
        }
        return checkAddWithMethodSignature(method, eventType);
    }
}

checkAdd中設(shè)置了兩種檢查方式,第一種是通過(guò)eventType也就是訂閱方法的入?yún)?lái)檢查,這種方式比較快,只需要看下之前有沒(méi)有這種入?yún)⒌姆椒ň涂梢粤?。注釋中也指出了通常一個(gè)類不會(huì)有多個(gè)入?yún)⑾嗤挠嗛喎椒ā?/p>

第二種是通過(guò)checkAddWithMethodSignature方法來(lái)檢查,源碼如下:

private boolean checkAddWithMethodSignature(Method method,Class<"); {
    methodKeyBuilder.setLength(0);
    methodKeyBuilder.append(method.getName());
    methodKeyBuilder.append(">").append(eventType.getName());
    String methodKey = methodKeyBuilder.toString();
    Class<");if (methodClassOld == null||methodClassOld.isAssignableFrom(methodClass)) {
        // Only add if not already found in a sub class
        return true;
    } else {
        // Revert the put, old class is further down theclasshierarchy
        subscriberClassByMethodKey.put(methodKey, methodClassOld);
        return false;
    }
}

通過(guò)method以及eventType來(lái)生成一個(gè)key,來(lái)存儲(chǔ)方法所在的類。其中methodClassOld == null ||methodClassOld.isAssignableFrom(methodClass)這個(gè)判斷條件對(duì)應(yīng)著兩種情況,methodClassOld == null說(shuō)明是入?yún)⑾嗤欠椒煌姆椒ㄕ诒惶砑?,直接返?b>true就可以了methodClassOld.isAssignableFrom(methodClass)這個(gè)條件是為了過(guò)濾掉父類被子類重寫(xiě)的方法,前面說(shuō)過(guò)了查找訂閱方法是從子類開(kāi)始遍歷的,此時(shí)如果子類重寫(xiě)了父類的訂閱方法,那么methodClassOld對(duì)應(yīng)的是子類,methodClass對(duì)應(yīng)的是父類,顯然這個(gè)判斷就會(huì)為false,之后進(jìn)入下面的else分支return false,也就是忽略掉父類被子類重寫(xiě)的方法。

查找訂閱方法基本就這么點(diǎn),查找完畢之后需要執(zhí)行訂閱操作,也就是register方法中的subscribe(subscriber, subscriberMethod);操作,直接看下該方法的實(shí)現(xiàn):

private void subscribe(Object subscriber, SubscriberMethodsubscriberMethod) {
    Class<");new Subscription(subscriber,subscriberMethod);
    CopyOnWriteArrayList subscriptions =subscriptionsByEventType.get(eventType);
    if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " +subscriber.getClass() + " already registered to event "
                    + eventType);
        }
    }
    int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {
        if (i == size || subscriberMethod.priority >subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }
    Listif (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);
    if (subscriberMethod.sticky) {
        if (eventInheritance) {
            // Existing sticky events of all subclasses of eventTypehave to be considered.
            // Note: Iterating over all events may be inefficientwith lots of sticky events,
            // thus data structure should be changed to allow a moreefficient lookup
            // (e.g. an additional map storing sub classes of superclasses: Class -> List).
            Setfor (Map.Entryif (eventType.isAssignableFrom(candidateEventType)) {
                    Object stickyEvent = entry.getValue();
                checkPostStickyEventToSubscription(newSubscriptin, stickyEvent);
                }
            }
        } else {
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription,stickyEvent);
        }
    }
}

subscriptionsByEventType這個(gè)Map是將eventType作為key保存其所對(duì)應(yīng)的訂閱方法的集合。該方法將剛查找到的方法添加到對(duì)應(yīng)的集合中去,添加時(shí)有這樣一層判斷i == size || subscriberMethod.priority >subscriptions.get(i).subscriberMethod.priority這表示這個(gè)集合里的方法會(huì)按照所設(shè)定的優(yōu)先級(jí)進(jìn)行排序。緊接著又出現(xiàn)了個(gè)MaptypesBySubscriber將訂閱者作為key保存一個(gè)Class的集合,暫時(shí)看不出有啥用,就先不管,最后再檢查下是不是粘性事件,如果是粘性事件就根據(jù)所保存的粘性事件來(lái)執(zhí)行該方法。eventInheritance也是在bulider中設(shè)置的,如果為true則會(huì)考慮事件的繼承性,如果現(xiàn)在有eventType為正在訂閱的方法的eventType的子類的粘性事件存在,那么這個(gè)粘性事件也會(huì)被正在訂閱的方法接收到,直接說(shuō)可能比較繞,舉個(gè)栗子,現(xiàn)在我有兩個(gè)事件,其中一個(gè)是另一個(gè)的子類,并且有兩個(gè)粘性訂閱方法,如下:

    class EventMessage {
  
    }

    class SubEventMessage extends EventMessage {

    }
    
    @Subscribe(sticky =  true)
    public void onEvent(EventMessage message) {
        // do something
    }

    @Subscribe(sticky =  true)
    public void onSubEvent(SubEventMessage message) {
        // do something
    }

當(dāng)執(zhí)行register時(shí),如果內(nèi)存中存在著一個(gè)類型為SubEventMessage的事件,那么訂閱的時(shí)候onEvent方法會(huì)被執(zhí)行,入?yún)⑹莾?nèi)存中類型為SubEventMessage的事件。

現(xiàn)在register大致就分析完了,再來(lái)看下unregister方法:

    public synchronized void unregister(Object subscriber) {
        Listif (subscribedTypes != null) {
            for (Class<");else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

unregister方法十分簡(jiǎn)單,typesBySubscriber是剛才在進(jìn)行訂閱的時(shí)候不知道用來(lái)干什么的Map,現(xiàn)在知道是在取消訂閱時(shí)用到的,這個(gè)Map將訂閱者作為key,將其所有的訂閱方法的eventType存入到對(duì)應(yīng)的List中去,取消訂閱時(shí)將這個(gè)List取出來(lái),遍歷去移除對(duì)應(yīng)的訂閱方法,具體實(shí)現(xiàn)在unsubscribeByEventType中,也十分簡(jiǎn)單,就不贅述了。

訂閱和取消訂閱都看過(guò)了,還差個(gè)發(fā)送事件,發(fā)送事件分為postpostSticky兩種,先看post

    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

currentPostingThreadState是個(gè)ThreadLocal,然后從中取出當(dāng)前線程的postingState,也就是說(shuō)每個(gè)線程都會(huì)維護(hù)一個(gè)自己的posting狀態(tài),之后會(huì)有個(gè)循環(huán)將事件隊(duì)列清空,通過(guò)postSingleEvent方法來(lái)進(jìn)一步處理:

private void postSingleEvent(Object event, PostingThreadStatepostingState) throws Error {
    Class<");boolean subscriptionFound = false;
    if (eventInheritance) {
        Listint countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<");else {
        subscriptionFound = postSingleEventForEventType(event,postingState, eventClass);
    }
    if (!subscriptionFound) {
        if (logNoSubscriberMessages) {
            logger.log(Level.FINE, "No subscribers registered forevent " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass !=NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}

同樣是通過(guò)eventInheritance來(lái)判斷是否要涉及eventType的父類,之后再通過(guò)postSingleEventForEventType方法的返回值來(lái)得到該事件是否被處理,如果沒(méi)有被處理,那么會(huì)返回false進(jìn)入下一個(gè)分支,logNoSubscriberMessagessendNoSubscriberEvents都是在builder中傳入的,前者用于沒(méi)有訂閱者處理事件時(shí)打印日志,后者用于沒(méi)有訂閱者處理事件時(shí)發(fā)送一個(gè)NoSubscriberEvent類型的事件,所以具體是怎么處理事件的還要繼續(xù)看postSingleEventForEventType方法:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<"); {
        CopyOnWriteArrayList subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

postSingleEventForEventType方法從subscriptionsByEventType中去獲取對(duì)應(yīng)事件類型的所有訂閱者,如果沒(méi)有訂閱者就返回false表示事件沒(méi)有被處理,否則就遍歷所有的訂閱者,通過(guò)postToSubscription方法來(lái)處理事件,接著往里看:

private void postToSubscription(Subscription subscription, Objectevent, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case POSTING:
            invokeSubscriber(subscription, event);
            break;
        case MAIN:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case MAIN_ORDERED:
            if (mainThreadPoster != null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                // temporary: technically not correct as poster notdecoupled from subscriber
                invokeSubscriber(subscription, event);
            }
            break;
        case BACKGROUND:
            if (isMainThread) {
                backgroundPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC:
            asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknown thread mode: " +subscription.subscriberMethod.threadMode);
    }
}

在這個(gè)方法內(nèi)終于看到通過(guò)區(qū)分注解中的threadMode來(lái)區(qū)分不同的處理方式了,先來(lái)看下這幾種threadMode分別代表什么意思:

Mode 含義
POSTING 在當(dāng)前線程執(zhí)行
MAIN 在主線程執(zhí)行
MAIN_ORDERED 在主線程有序執(zhí)行
BACKGROUND 在后臺(tái)線程執(zhí)行
ASYNC 在新的線程執(zhí)行

可以看到有幾個(gè)差不多,那具體有什么區(qū)別呢?直接從代碼里看,先說(shuō)明幾個(gè)東西,invokeSubscriber就是直接調(diào)用訂閱方法,還有幾個(gè)后綴為poster的變量暫時(shí)先理解為調(diào)用了enqueue方法后,訂閱方法就會(huì)在某個(gè)時(shí)間被執(zhí)行,后面再詳細(xì)講。

現(xiàn)在可以看代碼了,POSTING沒(méi)什么好說(shuō)的,直接調(diào)用invokeSubscriber,也就是說(shuō)在調(diào)用eventBus.post的線程執(zhí)行。

MAINMAIN_ORDERED都是在主線程執(zhí)行,后者的ORDERED體現(xiàn)在什么地方呢,先看下MAIN的分支,其中通過(guò)mainThreadPoster.enqueue插入的事件會(huì)在主線程執(zhí)行,判斷當(dāng)前線程是否是主線程來(lái)決定直接調(diào)用訂閱方法還是通過(guò)mainThreadPoster來(lái)發(fā)布,這里應(yīng)該沒(méi)什么疑惑的,主要是MAIN_ORDERED

 if (mainThreadPoster != null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                // temporary: technically not correct as poster notdecoupled from subscriber
                invokeSubscriber(subscription, event);
            }

mainThreadPoster不為空時(shí),通過(guò)mainThreadPoster來(lái)發(fā)布事件,為空時(shí)直接調(diào)用訂閱方法,說(shuō)好的在主線程調(diào)用呢?這里注釋也說(shuō)明了是不正確的,實(shí)際上mainThreadPoster為空本身就是種異常情況,具體可以看下它的初始化過(guò)程,這里就不細(xì)說(shuō)了。所以下面的else分支就先不管了,那么為什么說(shuō)通過(guò)mainThreadPoster發(fā)布的事件就是“有序”的呢,實(shí)際上mainThreadPoster內(nèi)部實(shí)現(xiàn)是個(gè)handler,可以將事件post到主線程中去執(zhí)行,所以說(shuō)是有序的,這里簡(jiǎn)單說(shuō)明下原因:

主線程維護(hù)著一個(gè)消息隊(duì)列,循環(huán)從里面取出消息來(lái)處理,我們知道可以通過(guò)viewpost方法來(lái)獲取它繪制完成之后的寬高,原因是post方法里的事件會(huì)被插入到消息隊(duì)列的尾部,而viewmeasure,layout,draw都在新插入的消息的前面,所以當(dāng)post的方法執(zhí)行時(shí),view肯定已經(jīng)繪制好了。

handler通過(guò)sendMessage發(fā)送的消息也會(huì)被插入到主線程消息隊(duì)列的尾部,這就是“有序”,比如現(xiàn)在有一個(gè)ImageView,在它的onMeasure中去發(fā)布一個(gè)事件,如果訂閱方法的模式是MAIN那么會(huì)在onMeasure中調(diào)用訂閱方法,而如果模式是MAIN_ORDERED那么會(huì)在ImageView繪制完成后調(diào)用訂閱方法。

再來(lái)看下BACKGROUNDASYNC的區(qū)別:

case BACKGROUND:
    if (isMainThread) {
        backgroundPoster.enqueue(subscription, event);
    } else {
        invokeSubscriber(subscription, event);
    }
    break;
case ASYNC:
    asyncPoster.enqueue(subscription, event);
    break;

其中backgroundPosterasyncPoster都會(huì)開(kāi)啟一個(gè)新線程來(lái)執(zhí)行訂閱方法,暫時(shí)當(dāng)成是一樣的就行,那么區(qū)別就是BACKGROUND模式如果在子線程post一個(gè)事件,那么會(huì)直接在該線程調(diào)用訂閱方法,只有在主線程post事件才會(huì)開(kāi)啟一個(gè)新線程。而ASYNC模式,不管是在哪post事件,都會(huì)開(kāi)啟一個(gè)新線程來(lái)調(diào)用訂閱方法。

最后再看下幾個(gè)poster基本上就看完了,幾個(gè)poster都實(shí)現(xiàn)了同一個(gè)接口Poster

interface Poster {

    /**
     * Enqueue an event to be posted for a particular subscription.
     *
     * @param subscription Subscription which will receive the event.
     * @param event        Event that will be posted to subscribers.
     */
    void enqueue(Subscription subscription, Object event);
}

可以看到里面只有一個(gè)需要實(shí)現(xiàn)的方法enqueue,是用來(lái)插入事件的,這個(gè)接口被三個(gè)類實(shí)現(xiàn),分別是HandlerPoster,BackgroundPosterAsyncPoster,上面的mainThreadPoster對(duì)應(yīng)的就是HandlerPoster,這三個(gè)類中都有個(gè)類型為PendingPostQueue的成員變量,這是個(gè)事件隊(duì)列,具體實(shí)現(xiàn)就不看了,這個(gè)隊(duì)列提供了入隊(duì)和出隊(duì)的方法。

先看下HandlerPosterenqueue方法:

public class HandlerPoster extends Handler implements Poster {
    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }
}

HandlerPoster繼承了Handler,調(diào)用enqueue方法后會(huì)向事件隊(duì)列中插入一個(gè)事件,然后將標(biāo)記位handlerActive設(shè)置為true表示正在處理事件,然后調(diào)用sendMessage發(fā)送消息通知處理事件。PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);這行是用來(lái)獲取一個(gè)消息隊(duì)列的Node用來(lái)插入到隊(duì)列中去,EventBus維護(hù)著一個(gè)pool用來(lái)保存閑置的Node當(dāng)有需要時(shí)從中取出一個(gè)給事件使用,pool不夠用時(shí)才會(huì)new新的Node出來(lái),具體可以看下PendingPost,這樣做的好處是可以避免頻繁創(chuàng)建對(duì)象帶來(lái)的開(kāi)銷(xiāo)。

再看下HandlerPosterhandleMessage方法:

    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(pendingPost);
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }

首先會(huì)記錄下開(kāi)始處理事件的時(shí)間,然后從事件隊(duì)列中取出事件,如果為空就將handlerActive設(shè)置為false直接return了,如果不為空,就調(diào)用eventBus.invokeSubscriber(pendingPost);來(lái)調(diào)用訂閱方法,執(zhí)行完后,再看下時(shí)間,如果超出了規(guī)定的時(shí)間那么重新發(fā)送一條消息,本次消息處理結(jié)束,等下次輪到自己的時(shí)候再處理事件,畢竟不能一直處理隊(duì)列里的事件而阻塞了主線程,如果沒(méi)有超出規(guī)定事件,那么說(shuō)明還可以有事件可以處理下一個(gè)事件,就會(huì)再次進(jìn)入循環(huán)。

BackgroundPosterAsyncPoster其實(shí)和HandlerPoster差不多,只是沒(méi)有用Handler而是用了線程池去處理事件,具體就不看了。

對(duì)了,還有個(gè)發(fā)送粘性事件:

public void postSticky(Object event) {
    synchronized (stickyEvents) {
        stickyEvents.put(event.getClass(), event);
    }
    // Should be posted after it is putted, in case the subscriberwants to remove immediately
    post(event);
}

就是在stickyEvents這個(gè)map里存一下。

好了,完了。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/7397.html

相關(guān)文章

  • EventBus源碼分析

    摘要:進(jìn)入源碼分析我們從的注冊(cè)開(kāi)始入手。關(guān)閉此功能將改善事件的發(fā)布。創(chuàng)建線程池我們將此段代碼逐步分析這步主要是進(jìn)行初始化話一下必要的參數(shù),如代碼注解所示。必須在線程同步中進(jìn)行。必須保持線程安全的,所以這里使用了。 簡(jiǎn)介 前面我學(xué)習(xí)了如何使用EventBus,還有了解了EventBus的特性,那么接下來(lái)我們一起來(lái)學(xué)習(xí)EventBus的源碼,查看EventBus的源碼,看看EventBus給我們...

    ChristmasBoy 評(píng)論0 收藏0
  • Android開(kāi)源架構(gòu)

    摘要:音樂(lè)團(tuán)隊(duì)分享數(shù)據(jù)綁定運(yùn)行機(jī)制分析一個(gè)項(xiàng)目搞定所有主流架構(gòu)單元測(cè)試一個(gè)項(xiàng)目搞定所有主流架構(gòu)系列的第二個(gè)項(xiàng)目。代碼開(kāi)源,展示了的用法,以及如何使用進(jìn)行測(cè)試,還有用框架對(duì)的進(jìn)行單元測(cè)試。 Android 常用三方框架的學(xué)習(xí) Android 常用三方框架的學(xué)習(xí) likfe/eventbus3-intellij-plugin AS 最新可用 eventbus3 插件,歡迎品嘗 簡(jiǎn)單的 MVP 模...

    sutaking 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<