EventBusソース試読(三)


転載は出典を明記してください:【Gypsophilaのブログ】http://blog.csdn.net/astro_gypsophila/article/details/75330316
EventBus基本使用とステップアップ構成EventBusソース試読(一)EventBusソース試読(二)EventBusソース試読(三)
ソース試読のunregister
// EventBus   
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
    //               
    List> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        //                       
        for (Class> eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

// EventBus   
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
    //         Subscription   , Subscription              
    List subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions != null) {
        int size = subscriptions.size();
        //   Subscription          ,              Subscription   
        for (int i = 0; i < size; i++) {
            Subscription subscription = subscriptions.get(i);
            if (subscription.subscriber == subscriber) {
                subscription.active = false;
                subscriptions.remove(i);
                i--;
                size--;
            }
        }
    }
}

unregisterの論理は比較的簡単で、register時に記録されたいくつかの集合からサブスクライバのいくつかの情報を削除することである.これによりpost時にメッセージをループして発行すると受信されません.さらにunsubscribeByEventType()のforループは、サブスクライバの下に複数の同じイベントを購読できる応答関数であるため、見つけるとbreakではなく、forループを完全に遍歴する必要がある.
ソース試読の購読者インデックス
このセクションでは、EventBusの基本的な使用とステップアップ構成について説明したが、Subscriber indexはコンパイル中にEventBus annotation processor(注釈プロセッサ)によって作成され、これにより、より迅速にサブスクライバを取得し、応答イベントをトリガーすることができる.
EventBusの基本的な使用とステップアップ構成で使用されるプレゼンテーションインタフェースは、Activity First->Activity Second->Activity Thirdの例です.MyEventBusIndexのフルネームについてはbuild.gradleは自由に構成されていますが、全体的にapp/build/generated/source/apt/debug/パスの下にあります.
build.gradle構成
android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ]
            }
        }
    }
    ...
}

構成するgradleは、本当に有効にします.次のコードを追加するだけでいいです.
EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
//   
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();

MyEventBusIndexコンテンツ
/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap, SubscriberInfo>();

        putIndex(new SimpleSubscriberInfo(com.gypsophila.eventbustest.ActivityThird.class, true,
                new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onStickyEvent", com.gypsophila.eventbustest.events.MessageEvent.class,
                    ThreadMode.MAIN, 0, true),
            new SubscriberMethodInfo("onMessageEvent", com.gypsophila.eventbustest.events.MessageEvent.class,
                    ThreadMode.MAIN),
        }));

        putIndex(new SimpleSubscriberInfo(com.gypsophila.eventbustest.ActivityFirst.class, true,
                new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onMessageEvent1", com.gypsophila.eventbustest.events.MessageEvent.class,
                    ThreadMode.POSTING, 1, false),
            new SubscriberMethodInfo("onMessageEvent2", com.gypsophila.eventbustest.events.MessageEvent.class,
                    ThreadMode.POSTING, 2, false),
            new SubscriberMethodInfo("onMessageEvent3", com.gypsophila.eventbustest.events.MessageEvent.class),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}

以上、すべてのサブスクリプションクラスでサブスクリプションされたイベントに対応する応答関数を記録した.コンパイル期間にこのようなインデックスが確立されたため、このようなサブスクライバクラスとそのクラスの応答関数との対応関係は、実行期間に反射取得方法を必要とせず、最適化と言える.
//   addIndex   
EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();

ここでのaddIndex()インデックスクラスが生成したListインデックスセットを追加する操作は、最終的にSubscriberMethodFinderクラス内のprivate List subscriberInfoIndexes;に付与される.このクラスは、register操作でサブスクライバの応答関数を検索する重要な実装です.
// SubscriberMethodFinder   
private List findUsingInfo(Class> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    //      subscriberClass     null,     while   
    while (findState.clazz != null) {
        //      
        findState.subscriberInfo = getSubscriberInfo(findState);
        //                    
        if (findState.subscriberInfo != null) {
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) {
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
            //                  ,        
            //             ,      
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}

// SubscriberMethodFinder   
private SubscriberInfo getSubscriberInfo(FindState findState) {
    if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
        SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
        if (findState.clazz == superclassInfo.getSubscriberClass()) {
            return superclassInfo;
        }
    }
    //        
    if (subscriberInfoIndexes != null) {
        //                 ,   SubscriberInfo   
        // SubscriberInfo                 
        for (SubscriberInfoIndex index : subscriberInfoIndexes) {
            SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
            if (info != null) {
                return info;
            }
        }
    }
    return null;
}

次の図のような新しい検索の流れですが、その後も同じサブスクライバを登録し続けると、キャッシュから直接取り出します.EventBus 源码试读(三)_第1张图片
フローチャートから分かるように、EventBusは異なる方法で、できるだけ性能を向上させることができると思います.反射を使用することで大きなパフォーマンスの問題が発生するわけではありません.使いやすさに注目しなければなりません.プロジェクトで使用するのは簡単です.
ここまで来ると、EventBusのメインフローもあまり見られません.しかし、他の細部については見る価値があります.結局、EventBusというライブラリの種類は多くなく、ゆっくり見て、ゆっくり勉強するのに適しています.大ライブラリの細部に陥って北の悩みが見つからないことを避けました.
ここではEventBusと放送の違いについて考えてみましょう.
  • の両者は類似している.Androidでの放送は、放送送信者と放送受信者の2つの側面に分けられ、通常、BroadcastReceiverとは放送受信者のことです(ブロードキャスト受信機).ブロードキャスト:ある場所でブロードキャストを登録し、別の場所でactionに対してブロードキャストを送信し、データを転送し、登録に対応する場所でブロードキャストを受信することができる.EventBus:サブスクリプション/パブリケーションのパターンに基づく.データを受信する必要がある場所では登録とサブスクリプションを行い、データをパブリッシュする必要がある場所でパブリッシュすると、登録した場所で受信できる. 簡単に言えば、二人がどのように通信するかを約束し、一人がメッセージを発表し、もう一人の約束した人がすぐにあなたのメッセージを受信します.EventBusは、androidサブスレッドがUIスレッドを操作する問題を考慮することなく、イベントをどこで発表しても、受信者はすぐにメッセージを受信することができます.
  • 両者の違い.(1)EventBusにはイベント、サブスクリプション、パブリケーションの3つの主要な要素があります.ブロードキャストの2つの要素:サブスクリプションとパブリケーションですが、ブロードキャストはApp全体についてです.(2)BroadcastReceiverはコンポーネントで、機能リストに登録する必要があります.EventBusは登録する必要はありません.(3)BroadcastReceiverは1つのことしかできませんが、EventBusはマルチイベント処理が良いです.(4)異なるシーンでの適用性:1)同じApp内部の同じコンポーネント内のメッセージ通信(単一または複数のスレッド間)は,実際のアプリケーションではブロードキャストメカニズムは使用されないに違いない(使用可能であるが)、拡張変数の役割ドメイン、インタフェースベースのコールバック、Handler-post/Handler-Messageなどの方法を使用しても、このような問題を直接処理することができ、ブロードキャストメカニズムを使用すると、明らかに「鶏を殺す牛刀」のような感じがする.2)同じapp内部の異なるコンポーネント間のメッセージ通信(単一プロセス)このようなニーズに対しては,教義が複雑な場合に単純にインタフェースベースのコールバックなどで扱いにくい場合があり,この場合EventBusなどをそのまま用いることができるのに対し,EventBusは同一プロセスであるため,そのようなニーズを処理するのに非常に適しており,かつ容易である.実際の業務に応じて放送メカニズムを使用するのは非常に適切である.

  • 以上の引用は修正する勇気がなく、両者の使用の簡便性と異なるシーンの適用を覚えておくだけです.
    参考:【Android攻略(35)】EventBusイベントバス配布ライブラリ