日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

EventBus源码分析

發(fā)布時間:2025/3/8 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 EventBus源码分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

簡介

前面我學(xué)習(xí)了如何使用EventBus,還有了解了EventBus的特性,那么接下來我們一起來學(xué)習(xí)EventBus的源碼,查看EventBus的源碼,看看EventBus給我們帶來什么驚喜以及編程思想。

這個圖我們從一開始就一直放置在上面了。我們在來回顧一下,EventBus的官網(wǎng)是怎么定義它的呢?
EventBus是Android和Java的發(fā)布/訂閱(觀察者模式)事件總線。
我們大概了解了EventBus的構(gòu)建思想。接下來我們進入源碼學(xué)習(xí)吧。

進入源碼分析

我們從EventBus的注冊開始入手。

EventBus.getDefault().register(this); public static EventBus getDefault() {if (defaultInstance == null) {synchronized (EventBus.class) {if (defaultInstance == null) {//創(chuàng)建了EventBus實例,進入下面的方法defaultInstance = new EventBus(); }}}return defaultInstance;}

上面的方法是一個雙重校驗的單例。

public EventBus() {this(DEFAULT_BUILDER); //private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();}

DEFAULT_BUILDER是EventBusBuilder.class實例來創(chuàng)建的,這個類非常重要:使用自定義參數(shù)創(chuàng)建EventBus實例,還允許自定義默認EventBus實例,如前面的例子使用索引、配置EventBus的配置&事件的優(yōu)先級&使用索引(四)等就是通過這個類來實現(xiàn)的,大家可以回顧一下。進入初始化一下必要的參數(shù)的構(gòu)造方法EventBus(EventBusBuilder builder),如下

EventBus(EventBusBuilder builder) {logger = builder.getLogger(); /初始化LoggersubscriptionsByEventType = new HashMap<>(); //存儲訂閱事件的typesBySubscriber = new HashMap<>(); //存儲相關(guān)訂閱者class列表,key是注冊者的對象,value是訂閱者的class列表stickyEvents = new ConcurrentHashMap<>(); //粘性事件//下面這4個實例就是我們設(shè)置方法``threadMode = ThreadMode.xxx``//*1mainThreadSupport = builder.getMainThreadSupport();mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;backgroundPoster = new BackgroundPoster(this);asyncPoster = new AsyncPoster(this);//獲取注冊者信息索引(添加由EventBus的注釋預(yù)處理器生成的索引)indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;//初始訂閱方法查找器。這個類主要具有查找訂閱的方法,繼續(xù)往下看subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex);logSubscriberExceptions = builder.logSubscriberExceptions; //是否有日記訂閱,默認truelogNoSubscriberMessages = builder.logNoSubscriberMessages;//是否有日記信息,默認 truesendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;//是否發(fā)送訂閱異常事件,默認truesendNoSubscriberEvent = builder.sendNoSubscriberEvent; //是否發(fā)送沒有訂閱事件,默認truethrowSubscriberException = builder.throwSubscriberException; //是否拋出異常處理//默認情況下,EventBus會考慮事件類層次結(jié)構(gòu)(將通知超類的注冊者)。 關(guān)閉此功能將改善事件的發(fā)布。對于直接擴展Object的簡單事件類,我們測量事件發(fā)布的速度提高了20%。eventInheritance = builder.eventInheritance; executorService = builder.executorService; //創(chuàng)建線程池}

我們將此段代碼逐步分析.
這步主要是進行初始化話一下必要的參數(shù),如代碼注解所示。
下面這段代碼就是我們常用的@Subscribe(threadMode = ThreadMode.xxx);初始化。一般常用的就是以下4種。

mainThreadSupport = builder.getMainThreadSupport(); mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this);

我們來看看builder.getMainThreadSupport()方法返回的是MainThreadSupport接口,表示為支持Android主線程。
上面的4個線程中都持有 PendingPostQueue 等待發(fā)送的隊列實例。
由mainThreadSupport.createPoster(this)創(chuàng)建一個HandlerPoster而該類繼承了Handle,并且初始化了一個等待發(fā)布隊列。代碼如下。

public interface MainThreadSupport {boolean isMainThread();Poster createPoster(EventBus eventBus);class AndroidHandlerMainThreadSupport implements MainThreadSupport {private final Looper looper;public AndroidHandlerMainThreadSupport(Looper looper) {this.looper = looper;}@Overridepublic boolean isMainThread() {return looper == Looper.myLooper();}@Overridepublic Poster createPoster(EventBus eventBus) {return new HandlerPoster(eventBus, looper, 10);}} } subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex);

上面代碼在這里主要初始化訂閱的方法查找器。下面會講解到它是如何進行訂閱方法的。
我們這這里知道了EventBus初始化,然后相關(guān)的實例的創(chuàng)建,接下來我我們進入到register(this)方法的調(diào)用如下方法。

public void register(Object subscriber) {//獲取當(dāng)前注冊者對象的Class。Class<?> subscriberClass = subscriber.getClass(); //通過該注冊者的`Class`來獲取當(dāng)前注冊者里面由`@Subscriber`注解綁定的方法。List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//必須在線程同步中進行。synchronized (this) {for (SubscriberMethod subscriberMethod : subscriberMethods) {subscribe(subscriber, subscriberMethod);}}}

上面的代碼表示的是給注冊者接收事件。 傳遞當(dāng)前所注冊的對象,如Activity、Fragment。

  • 注意: 注冊者如果不再接收信息,必須調(diào)用unregister(Object)方法,表示解除注冊則該訂閱者將不再接收到數(shù)據(jù)了,如果不進行解除將可能出現(xiàn)內(nèi)存泄漏。一般在onDestroy方法解除注冊后面會講解到。 在注冊者中擁有必須由@Subscribe注解的方法。@Subscribe還允許配置ThreadMode和優(yōu)先級、是否是粘性行為。

接著,我們進入List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);方法。

//private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>(); //線程安全List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {//從Map集合中獲取訂閱方法列表List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//判斷當(dāng)前獲取方法是否為空if (subscriberMethods != null) {return subscriberMethods;}//通過EventBusBuilder.ignoreGeneratedIndex//是否忽略配置索引,默認是忽略索引if (ignoreGeneratedIndex) {//1.通過反射獲取方法列表subscriberMethods = findUsingReflection(subscriberClass);} else {//2.通過索引方式獲取訂閱方法列表subscriberMethods = findUsingInfo(subscriberClass);}//是否訂閱方法為空,如果為空則表示該訂閱者里面的方法都不符合EventBus訂閱方法的規(guī)則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;} }

我們逐步分析該段代碼。
該段代碼通過注冊者的類來獲取當(dāng)前dingy的方法列表,如果不為空則直接返回訂閱方法。
通過反射來查找訂閱方法,如果該方法為空則拋出異常:該訂閱者的方法和其超類沒有@Subscriber注解的共有方法(即表示不符合EventBus訂閱方法的規(guī)則)。如果不為空則存儲到ConcurrentHashMap集合中。
這里的是由ConcurrentHashMap集合存儲是以當(dāng)前訂閱者的class為key,而將其由@Subscriber綁定的方法添加到List中,,就是集合的value。必須保持線程安全的,所以這里使用了ConcurrentHashMap。

  • 1.是否忽略索引設(shè)置,該方法表示忽略設(shè)置索引,進入該方法findUsingReflection(Class<?> subscriberClass),通過反射進行獲取List<SubscriberMethod>
  • 注:設(shè)置索引在EventBus的配置&事件的優(yōu)先級&使用索引(四)這里說的,大家可以去看看。
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {FindState findState = prepareFindState();//準備查找狀態(tài)findState.initForSubscriber(subscriberClass);// 初始化訂閱者信息while (findState.clazz != null) {//循環(huán)獲取訂閱者的class是否為空//通過反射獲取訂閱方法,// 3.該方法下面分析findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); //刪除超類class}獲取訂閱方法listreturn getMethodsAndRelease(findState);}

上面的代碼主要是通過反射來獲取相關(guān)的訂閱方法,里面由靜態(tài)內(nèi)部類FindState進行管理相關(guān)信息,由于上面的方法和下面索引的方法都將調(diào)用同一個方法,所以放在下面來將講解,請看下面信息。

  • 2.是否忽略索引設(shè)置,該方法表示的設(shè)置了索引,進入findUsingInfo(Class<?> subscriberClass)方法,如下。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {FindState findState = prepareFindState(); //準備查找狀態(tài)findState.initForSubscriber(subscriberClass);// 初始化訂閱者信息while (findState.clazz != null) { //循環(huán)獲取訂閱者的class是否為空findState.subscriberInfo = getSubscriberInfo(findState);//獲取獲取訂閱者信息,這里如果使用添加索引的話,這里將能獲取到索引的相關(guān)信息。if (findState.subscriberInfo != null) { //獲取訂閱方法SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();for (SubscriberMethod subscriberMethod : array) {//進行等級檢查,并存儲到Map集合中,該方法checkAdd是FindState.class中的方法 ,key是@Subscriber中參數(shù)的class,value是該subscriberMethod.method,也就是@Subscribe中的方法如:public void onMessageEvent(MessageEvent event)if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {//將該訂閱方法添加到列表中findState.subscriberMethods.add(subscriberMethod);}}} else {//3.通過使用反射的方式來獲取,和上面忽略索引調(diào)用到同一個方法,這里將解析findUsingReflectionInSingleClass(findState);}//清除父類的方法findState.moveToSuperclass();}//獲取訂閱方法listreturn getMethodsAndRelease(findState);}

分析本段代碼。
首先進入查找的準備狀態(tài),通過默認狀態(tài)池返回狀態(tài)信息,主要存儲的是FindState實例。主要存儲的有訂閱者的class、訂閱者信息SubscriberInfo。訂閱者@Subscribe方法列表List<SubscriberMethod>等.
如果當(dāng)前訂閱者class不為空,則將獲取到訂閱者信息。這里分兩種情況。
如果使用添加索引的話,getSubscriberInfo(findState)該方法將獲取到訂閱信息,如果沒有使用索引的話則將調(diào)用findUsingReflectionInSingleClass(findState);該方法來獲取信息

  • 使用添加索引,并返回訂閱方法,該方法如下
//獲取訂閱方法SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();

由于AbstractSubscriberInfo類實現(xiàn)了SubscriberInfo接口,而SimpleSubscriberInfo繼承了AbstractSubscriberInfo并實現(xiàn)了getSubscriberMethods方法,代碼如下:
本段代碼在SimpleSubscriberInfo.class中。返回訂閱方法數(shù)組SubscriberMethod[]。

@Overridepublic synchronized SubscriberMethod[] getSubscriberMethods() {int length = methodInfos.length;SubscriberMethod[] methods = new SubscriberMethod[length];for (int i = 0; i < length; i++) {SubscriberMethodInfo info = methodInfos[i];methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,info.priority, info.sticky);}return methods;}
  • 3.如果沒有添加索引則進入該方法findUsingReflectionInSingleClass(findState);

通過反射來獲取訂閱者方法。這個方法有點長,慢慢看。

private void findUsingReflectionInSingleClass(FindState findState) {Method[] methods;try {// This is faster than getMethods, especially when subscribers are fat classes like Activities//該方法代替getMethods()方法,獲取該訂閱者class全部方法。methods = findState.clazz.getDeclaredMethods();} catch (Throwable th) {// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149methods = findState.clazz.getMethods(); //獲取該訂閱者class全部方法findState.skipSuperClasses = true; //設(shè)置跳過超類}for (Method method : methods) {int modifiers = method.getModifiers();//獲取修飾符if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { //通過與運算判斷當(dāng)前的修飾符,是否符合EventBus方法定義Class<?>[] parameterTypes = method.getParameterTypes(); //獲取參數(shù)類型if (parameterTypes.length == 1) { //因為EventBus方法中必須有參數(shù),所以當(dāng)參數(shù)為1時,符合要求//通過注解的形式@Subscribe獲取Subscribe,默認的Subscribe為(priority==0,sticky=false,threadMode=POSTING),就是說ThreadMode為POSTING,粘性為false,優(yōu)先級為0,如果方法中設(shè)置了相應(yīng)的值,則將是你設(shè)置的值。如threadMode=MAIN。Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);if (subscribeAnnotation != null) {Class<?> eventType = parameterTypes[0]; //獲取當(dāng)前參數(shù)的class//進行等級檢查,并存儲到Map集合中,該方法checkAdd是FindState.class中的方法 ,key是@Subscriber中參數(shù)的class,value是該subscriberMethod.method,也就是@Subscribe中的方法如:public void onMessageEvent(MessageEvent event)if (findState.checkAdd(method, eventType)) { // 獲取ThreadMode ,如MAINThreadMode threadMode = subscribeAnnotation.threadMode();//將訂閱方法添加到列表中findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));}}} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { //不符合EventBus訂閱方法的規(guī)則要求。拋出異常,提示該方法必須是@Subscribe注解,并且需要一個參數(shù)String methodName = method.getDeclaringClass().getName() + "." + method.getName();throw new EventBusException("@Subscribe method " + methodName +"must have exactly 1 parameter but has " + parameterTypes.length);}} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {//是一種非法的@Subscribe方法:必須是公共的,非靜態(tài)的,非抽象的String methodName = method.getDeclaringClass().getName() + "." + method.getName();throw new EventBusException(methodName +" is a illegal @Subscribe method: must be public, non-static, and non-abstract");}}}

該段代碼主要是獲取該注冊者的全部方法,并進行篩選出來符合EventBus的訂閱方法的規(guī)則,通過注解的形式來獲取訂閱方法,最后添加到查找狀態(tài)的列表中。
首先獲取的是修飾符,參數(shù)類型,再通過注解的形式來獲取訂閱方法。如下注解Subscribe ,如果不符合EventBus相關(guān)訂閱方法的規(guī)則將拋出異常提示,是否在方法上書寫了錯誤的方法。
接下來我們進入看看@Subscribe 訂閱方法是通過注解的形式來設(shè)置的。

@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe {//ThreadMode ,默認POSTINGThreadMode threadMode() default ThreadMode.POSTING;//粘性事件,默認falseboolean sticky() default false;//優(yōu)先級,默認0int priority() default 0; }

接下來進入getMethodsAndRelease(FindState findState)

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {//獲取到訂閱方法列表List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); findState.recycle(); //清空回收相關(guān)信息synchronized (FIND_STATE_POOL) {for (int i = 0; i < POOL_SIZE; i++) {if (FIND_STATE_POOL[i] == null) {FIND_STATE_POOL[i] = findState; //將查找狀態(tài)器findState,添加到狀態(tài)池FIND_STATE_POOL中,為下次直接從查找狀態(tài)池中獲取break;}}}return subscriberMethods; // 返回訂閱方法列表}

上面該方法通過FindState靜態(tài)內(nèi)部類獲取了訂閱的列表,然后被存儲到了ConcurrentHashMap集合中。并且存儲到狀態(tài)池中,為方便下次讀取。并且回收資源。
獲取到List<SubscriberMethod>訂閱列表后,再次回到了注冊方法中register(Object subscriber)進入到方法subscribe(subscriber, subscriberMethod);該方法通過循環(huán)進行遍歷

  • 注 此處必須是在線程同步中進行,所以添加synchronized。
//這里的參數(shù)subscriber表示的是訂閱者,如Activity等,subscriberMethod表示訂閱方法,該方法就是在subscriber里面 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {Class<?> eventType = subscriberMethod.eventType; //獲取事件類型,也就是參數(shù)的classSubscription newSubscription = new Subscription(subscriber, subscriberMethod);//通過事件類型參數(shù)class獲取CopyOnWriteArrayList<Subscription>列表,該類大家可以研究一下,//是寫時復(fù)制容器,即當(dāng)我們往`CopyOnWriteArrayList`容器添加元素時,先從原有的數(shù)組中拷貝一份出來,然后在新的容器做寫操作(添加元素),寫完之后,再將原來的數(shù)組引用指向到新數(shù)組的形式存儲數(shù)據(jù)的,它是線程安全的。CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);if (subscriptions == null) {subscriptions = new CopyOnWriteArrayList<>();subscriptionsByEventType.put(eventType, subscriptions); //添加到Map集合中} else {if (subscriptions.contains(newSubscription)) { //是否已經(jīng)存在了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) { //判斷優(yōu)先級subscriptions.add(i, newSubscription);//優(yōu)先級高的添加添加到CopyOnWriteArrayList容器最前面,只有一個的時候就是添加在第一位了。break;}}//獲取訂閱事件的class列表,即訂閱方法的參數(shù)class列表List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);if (subscribedEvents == null) {subscribedEvents = new ArrayList<>();//存儲到Map集合,key是訂閱者(即上面?zhèn)鬟f的Activity對象),value是訂閱事件列表typesBySubscriber.put(subscriber, subscribedEvents);}subscribedEvents.add(eventType); //將該事件類型class添加到訂閱事件列表中判斷當(dāng)前方法是否是粘性的if (subscriberMethod.sticky) {if (eventInheritance) {//必須考慮eventType的所有子類的現(xiàn)有粘性事件// Existing sticky events of all subclasses of eventType have to be considered.// Note: Iterating over all events may be inefficient with lots of sticky events,// thus data structure should be changed to allow a more efficient lookup// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();for (Map.Entry<Class<?>, Object> entry : entries) {Class<?> candidateEventType = entry.getKey();isAssignableFrom(Class<?> cls)方法表示的類型是否可以通過標識轉(zhuǎn)換或通過擴展引用轉(zhuǎn)換為此類對象表示的類型,則返回trueif (eventType.isAssignableFrom(candidateEventType)) {Object stickyEvent = entry.getValue();//將粘性事件添加到訂閱者列表中checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}} else {//將粘性事件添加到訂閱者列表中Object stickyEvent = stickyEvents.get(eventType);checkPostStickyEventToSubscription(newSubscription, stickyEvent);}}}

上面的方法中主要是通過獲取"事件類型"即訂閱方法中的參數(shù)class。然后將其添加到Map集合中,這里用到了CopyOnWriteArrayList(原理:是寫時復(fù)制容器,即當(dāng)我們往CopyOnWriteArrayList容器添加元素時,先從原有的數(shù)組中拷貝一份出來,然后在新的容器做寫操作(添加元素),寫完之后,再將原來的數(shù)組引用指向到新數(shù)組的形式存儲數(shù)據(jù)的,它是線程安全的。)
然后進行判斷是否設(shè)置優(yōu)先級,遍歷并添加到subscriptions列表中。
通過當(dāng)前的注冊者,獲取注冊者class列表,并添加到typesBySubscriber集合中,key是注冊者的class,如:Activity,而value就是訂閱方法中的參數(shù)class的列表。這個地方說明了,一個注冊者,可以擁有多個訂閱事件(方法),將其綁定起來,存儲到Map集合中。最后將該參數(shù)class添加到subscribedEvents.add(eventType);列表中。
下面方法是檢查粘性事件訂閱發(fā)送事件方法,如下

private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {if (stickyEvent != null) {// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)// --> Strange corner case, which we don't take care of here.//這段代碼我們到post發(fā)送事件的調(diào)用的時候講解。postToSubscription(newSubscription, stickyEvent, isMainThread());}}
  • 注:這里主要是檢查是否發(fā)送粘性發(fā)送事件,方法 postToSubscription我們到發(fā)送事件POST方法調(diào)用時講解。
  • 事件發(fā)送

接下來我進入post方法,事件發(fā)送。此時,我們回憶一下簡介中的圖:
post()==>EventBus==>將分發(fā)到各個訂閱事件中。也就是訂閱方法。我們來看看是如何進行操作的。代碼如下

EventBus.getDefault().post(new MessageEvent(message));

通過以上代碼我大概的知道,post()方法里面的參數(shù)是一個實體的對象,而該實體就是我們在訂閱方法中的參數(shù)實體。你發(fā)現(xiàn)了什么了嗎?
前邊我們已經(jīng)分析了,該注冊者的訂閱方法主要的存儲過程,接下來我們一起進入探究吧。方法跟蹤進入post()方法。

/** Posts the given event to the event bus. *///給訂閱事件,發(fā)送事件總線public void post(Object event) {//獲取當(dāng)前線程,即通過ThreadLocal本地線程來管理對應(yīng)的事件線程,并且初始化發(fā)送線程狀態(tài)PostingThreadStatePostingThreadState postingState = currentPostingThreadState.get();List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); //添加到事件隊列中//判斷當(dāng)前發(fā)送線程狀態(tài)是否是正在發(fā)送的事件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()) {//發(fā)送事件,發(fā)送完一個刪除一個,直到發(fā)送全部停止循環(huán)postSingleEvent(eventQueue.remove(0), postingState);}} finally {//設(shè)置標志改變postingState.isPosting = false;postingState.isMainThread = false;}}}

currentPostingThreadState.get()方法中我們知道

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {@Overrideprotected PostingThreadState initialValue() {return new PostingThreadState();}};

通過ThreadLocal這里就叫"本地線程"吧,來管理當(dāng)前的發(fā)送線程狀態(tài),每個發(fā)送線程將得到對應(yīng)一個PostingThreadState,而該PostingThreadState管理eventQueue信息,該信息主要存儲的是發(fā)送事件。
通過eventQueue.add(event)存儲該發(fā)送事件以后完成以后,就判斷當(dāng)前的發(fā)送事件狀態(tài)是否是正在發(fā)送中,如果還沒發(fā)送則當(dāng)該eventQueue不為為空的時候,進入循環(huán)發(fā)送該事件,發(fā)送完一個就刪除一個,直到發(fā)送完成為止。
進入方法postSingleEvent(Object event, PostingThreadState postingState)中。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {Class<?> eventClass = event.getClass();boolean subscriptionFound = false;if (eventInheritance) {//查找所有事件類型List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);int countTypes = eventTypes.size();for (int h = 0; h < countTypes; h++) {Class<?> clazz = eventTypes.get(h);//發(fā)送事件subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);}} else {subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);}if (!subscriptionFound) {if (logNoSubscriberMessages) {logger.log(Level.FINE, "No subscribers registered for event " + eventClass);}if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&eventClass != SubscriberExceptionEvent.class) {post(new NoSubscriberEvent(this, event));}}}

上面的方法首先獲取該事件類型的class然后傳遞到lookupAllEventTypes(eventClass)方法中,通過該方法獲取當(dāng)前發(fā)送事件的class,包括父類、實現(xiàn)的接口等等列表。所以一般情況下會返回當(dāng)前發(fā)送的事件,和Object.class(注:當(dāng)然了,如果該事件實現(xiàn)接口的話,也會包括實現(xiàn)的接口的。)列表即List<Class<?>>,然后進行遍歷進行或運算。
我們先進入lookupAllEventTypes(eventClass)方法,看看返回的事件類型,并且知道他存儲到Map集合中,即key是當(dāng)前事件class,value是該事件的所有類型,包括父類,接口等。

/** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {//private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>(); key是當(dāng)前事件類型的class,valu則是事件的所有類型,包括父類,接口等。本事例會得到的是MessageEvent.class、和Object.classsynchronized (eventTypesCache) {List<Class<?>> eventTypes = eventTypesCache.get(eventClass);if (eventTypes == null) {eventTypes = new ArrayList<>();Class<?> clazz = eventClass;while (clazz != null) {eventTypes.add(clazz); //添加到列表中//添加接口addInterfaces(eventTypes, clazz.getInterfaces());clazz = clazz.getSuperclass(); //獲取父類class}eventTypesCache.put(eventClass, eventTypes); //存儲d}return eventTypes;}}

看看方法postSingleEventForEventType(event, postingState, clazz),發(fā)送事件

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {CopyOnWriteArrayList<Subscription> subscriptions;synchronized (this) {//通過當(dāng)前的事件class,獲取訂閱事件列表subscriptions = subscriptionsByEventType.get(eventClass);}if (subscriptions != null && !subscriptions.isEmpty()) {for (Subscription subscription : subscriptions) {//對PostingThreadState進行賦值postingState.event = event;postingState.subscription = subscription;boolean aborted = false;try {//發(fā)送事件postToSubscription(subscription, event, postingState.isMainThread);aborted = postingState.canceled;} finally {//設(shè)置參數(shù)為空postingState.event = null;postingState.subscription = null;postingState.canceled = false; //設(shè)置標志}if (aborted) {break;}}return true;}return false;}

大家是否還記得在注冊的時候出現(xiàn)的CopyOnWriteArrayList<Subscription>在這里就用到了,通過發(fā)送事件的class獲取CopyOnWriteArrayList容器里面的訂閱事件信息,包括注冊者對象,訂閱方法等。然后遍歷并進行發(fā)送事件。在此方法發(fā)布postToSubscription()事件

/*** subscription:發(fā)布訂閱的事件處理器* event:當(dāng)前發(fā)布的事件* isMainThread:是否是在主線程中*/ private void postToSubscription(Subscription subscription, Object event, 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 not decoupled from subscriberinvokeSubscriber(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);}}

好了,這就是之前我們在注冊中有一個地方遺留下的,就是判斷是否是粘性狀態(tài)是調(diào)用的方法,大家往回看,就看到了在方法checkPostStickyEventToSubscription中有調(diào)用到該方法。
這里會根據(jù),在方法中所選的threadMode進行調(diào)用,

  • 1.MAIN,如果當(dāng)前是否是UI線程,則會進入到invokeSubscriber(subscription, event);方法中。否則將調(diào)用mainThreadPoster.enqueue(subscription, event);這個方法將交給HandlerPoster.class里面的enqueue(Subscription subscription, Object event)方法,HandlerPoster.class現(xiàn)實了該接口,移交給handle完成,大家可以進入HandlerPoster.class看看,這里就不說了。
  • 2.POSTING直接調(diào)用 invokeSubscriber(subscription, event);
  • 3.MAIN_ORDERED如果當(dāng)前mainThreadPoster不為空則調(diào)用 mainThreadPoster.enqueue(subscription, event);和MAIN進入HandlerPoster.class,反之調(diào)用invokeSubscriber(subscription, event);
  • 4.BACKGROUND如果當(dāng)前是主線程,則調(diào)用backgroundPoster.enqueue(subscription, event);,反之調(diào)用invokeSubscriber(subscription, event);
  • 5.ASYNC,異步方法調(diào)用,執(zhí)行 asyncPoster.enqueue(subscription, event);,方法進行跟蹤,該類有實現(xiàn)了Runnable接口,然后調(diào)用eventBus.invokeSubscriber(pendingPost);,最終將調(diào)用了invoke方法。
void invokeSubscriber(Subscription subscription, Object event) {try {subscription.subscriberMethod.method.invoke(subscription.subscriber, event);} catch (InvocationTargetException e) {handleSubscriberException(subscription, event, e.getCause());} catch (IllegalAccessException e) {throw new IllegalStateException("Unexpected exception", e);}}

invoke()這是一個本地的方法,將調(diào)用C/C++的到方法進行發(fā)布。最后將進入到訂閱方法中。并傳遞該事件到到訂閱的方法中。
好了,這里我們將post發(fā)布事件的方法簡單的分析了一下。整個EventBus的分析差不多完成了,但是,我們還有一點不能忘記就是解除綁定。接下來我們來看看解除綁定的方法。

  • 注:該方法一般生命周期的onDestroy()方法中進行解除綁定。

代碼如下:

EventBus.getDefault().unregister(this);

直接進入unregister(this)

/** Unregisters the given subscriber from all event classes. */public synchronized void unregister(Object subscriber) {List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);if (subscribedTypes != null) {for (Class<?> eventType : subscribedTypes) {unsubscribeByEventType(subscriber, eventType);}typesBySubscriber.remove(subscriber);} else {logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());}} /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. *//*** subscriber:指代當(dāng)前解除注冊的對象如Activity,* eventType:發(fā)送的事件類型,post函數(shù)的實體對象class*/ private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);if (subscriptions != null) {int size = subscriptions.size();for (int i = 0; i < size; i++) {Subscription subscription = subscriptions.get(i);if (subscription.subscriber == subscriber) {subscription.active = false;subscriptions.remove(i); //刪除i--; //目的是減少遍歷次數(shù)size--;}}} }

解除綁定,這里很簡單。這里就不一一進行解釋了,^_^。

總結(jié)

1.本篇文章主要對EventBus源碼進行簡單的分析。主要是進行了觀察者模式的一些高級運用。如果大家對觀察者模式理解不怎么清楚可以進入這里看看簡單的案例觀察者模式,內(nèi)容非常簡單。
2.相關(guān)的EvenBut的使用,請看之前的內(nèi)容。如EventBus認識(一)EventBus的ThreadMode使用以及分析(二)等等。
3.學(xué)習(xí)本篇文章中可以認識到一些常用的類如CopyOnWriteArrayList、ThreadLocal等,到時可以深入研究一下,有助我們提高。
4.一些編程思想,設(shè)計模式值得我們?nèi)W(xué)習(xí)的,如單例模式EventBus雙重校驗、建造者模式,EventBus構(gòu)造器的時候用到,用了初始化各個參數(shù)等等。面向接口編程而不針對實現(xiàn)編程。
5.如果有什么問題希望大家進行指正,好好學(xué)習(xí),一起進步。

總結(jié)

以上是生活随笔為你收集整理的EventBus源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

国产精品24小时在线观看 | 视频国产一区二区三区 | 国产精品手机在线观看 | 日韩国产在线观看 | 免费在线观看av | 婷婷丁香狠狠爱 | 在线观看免费版高清版 | 黄色av电影一级片 | 一区二区视频欧美 | 91在线免费看片 | 免费看黄的| 亚洲欧美日韩在线一区二区 | 久久电影中文字幕视频 | 久久一区二区三区超碰国产精品 | 中文字幕二区三区 | 国产免费观看久久 | 欧美日韩国产mv | a级成人毛片 | 91精品中文字幕 | a'aaa级片在线观看 | 美女搞黄国产视频网站 | 国产亚洲欧美一区 | 免费看日韩片 | 久久亚洲热 | 国产精品成人av久久 | 91毛片视频 | 免费在线看成人av | 狠狠地操| 亚洲精品视频在线观看网站 | 亚洲国产精品人久久电影 | 婷婷亚洲五月色综合 | 久久久免费看片 | 久久久久综合精品福利啪啪 | 日韩精品中文字幕一区二区 | 久久成人高清视频 | 久久久久久国产精品亚洲78 | 国产亚洲精品综合一区91 | 久久亚洲精品国产亚洲老地址 | 中文字幕资源在线观看 | 最新国产精品久久精品 | 五月婷婷视频在线 | 亚洲理论影院 | 国产专区在线看 | 久久人人爽人人爽 | 欧美极品久久 | 国产高清精| 在线看黄色av | 在线观看视频在线 | 欧美精品久久 | 亚洲美女免费精品视频在线观看 | 91精品视频免费看 | 91麻豆国产福利在线观看 | 色偷偷97 | 午夜在线国产 | 天天综合亚洲 | 国产精品中文字幕av | 久久麻豆精品 | 久久免费视频网 | 在线观看av不卡 | 激情五月婷婷激情 | 天天在线免费视频 | 99精品免费久久久久久久久日本 | 欧美日韩在线观看视频 | www.777奇米 | 国产一区二区在线播放 | 欧美日韩一区二区久久 | 日本不卡123 | 久久乐九色婷婷综合色狠狠182 | 午夜久久久久久久 | 麻豆91视频 | 成人资源在线观看 | 黄色免费观看网址 | 久草久草久草久草 | 日韩色区 | 青草视频在线播放 | 日韩av午夜在线观看 | 久草视频精品 | 亚洲免费婷婷 | 美女一级毛片视频 | 午夜精品电影一区二区在线 | 一区二区中文字幕在线播放 | 亚洲视频电影在线 | 日韩av三区| 白丝av在线 | 欧美精品v国产精品 | 日本在线观看视频一区 | 久久久久久久综合色一本 | 激情久久网 | 精品久久一 | 国产.精品.日韩.另类.中文.在线.播放 | 久青草视频 | 97国产在线观看 | 视频在线99 | 少妇精品久久久一区二区免费 | 亚洲 欧美 成人 | 亚洲天堂网在线播放 | 中文网丁香综合网 | 亚洲免费视频观看 | 免费看色视频 | 色国产精品一区在线观看 | 成人免费xyz网站 | 极品嫩模被强到高潮呻吟91 | 天堂网一区 | 精品a在线 | 五月天电影免费在线观看一区 | 美女网站在线看 | 中文字幕在线视频网站 | 91av视频在线观看免费 | 亚洲日本中文字幕在线观看 | 成人av在线看 | 国产精品黑丝在线观看 | 天天干天天射天天爽 | 一区免费在线 | 天堂v中文 | 日韩在线不卡视频 | 人人玩人人添人人澡97 | 中文字幕一区二区三区四区久久 | 在线高清av| 又湿又紧又大又爽a视频国产 | 日韩在线视频线视频免费网站 | 欧美精品久 | 一二三四精品 | av黄免费看 | 在线 日韩 av | 国产aaa大片| 色com网| 国产综合小视频 | 欧美成人91 | 日本资源中文字幕在线 | 91麻豆精品国产91久久久久久久久 | 综合激情婷婷 | 人人澡人人舔 | 亚洲精品乱码久久久久久按摩 | 国产在线视频在线观看 | 国产理论免费 | 亚洲精品视频在线观看免费视频 | 欧美激情精品久久久久久免费印度 | 成人a视频片观看免费 | 国模精品在线 | 色操插 | 天天爽天天爽夜夜爽 | 免费a级黄色毛片 | 成人av电影免费在线观看 | 欧美精品一级视频 | 久久男人免费视频 | 国产美女免费观看 | 成人97人人超碰人人99 | 精品一区二区三区在线播放 | 91精品国产麻豆国产自产影视 | 亚洲国产精品视频 | 欧美一级特黄aaaaaa大片在线观看 | 午夜精品婷婷 | 国内精品在线观看视频 | 国产91精品一区二区麻豆亚洲 | 国产精品乱码一区二区视频 | 在线观看视频国产 | 国产高清久久久久 | 国产精品青草综合久久久久99 | 一区二区理论片 | 91精品啪在线观看国产 | 欧美色图30p | 久久亚洲美女 | 欧美日韩不卡一区二区 | 日本久久综合视频 | 最近字幕在线观看第一季 | 国产a精品 | 亚洲色图22p| 日韩69视频 | 女人18精品一区二区三区 | 国产高清视频免费最新在线 | 午夜色大片在线观看 | 日韩xxxbbb | 国产精品手机在线播放 | 久久久久99999 | 亚洲黄色免费电影 | 日本久久91 | 久久久午夜精品理论片中文字幕 | www免费看片com | 久久久久福利视频 | 久久一久久| 在线观看黄色免费视频 | 99视频在线免费播放 | 亚洲人天堂 | 精品99999| 国产精品一区二区美女视频免费看 | 综合网在线视频 | 99久久综合国产精品二区 | 亚洲成年人免费网站 | 深爱激情站 | 欧美日韩xx | 黄色网在线免费观看 | 日韩av网站在线播放 | 久久狠狠婷婷 | 一区二区三区免费在线观看视频 | 91黄色免费看 | 午夜在线免费观看视频 | 99精品一区二区三区 | 欧美日韩精品在线视频 | 香蕉视频最新网址 | 国产精品九九久久久久久久 | 偷拍精品一区二区三区 | www.夜色321.com| 成人av动漫在线 | 97操操| 精品一二三四五区 | 在线播放第一页 | 欧美国产日韩在线视频 | 欧美日韩高清一区二区 国产亚洲免费看 | 视频福利在线观看 | 日韩网站一区二区 | 国产一二区精品 | 五月婷婷在线视频 | 在线免费高清一区二区三区 | 午夜免费视频网站 | 午夜国产一区二区 | 97超碰超碰久久福利超碰 | 九九热有精品 | 97在线观看免费高清完整版在线观看 | 国产视频一区二区在线播放 | 99久久er热在这里只有精品66 | 日韩综合视频在线观看 | 日韩成人看片 | 麻豆传媒在线免费看 | 最近免费中文字幕大全高清10 | 97人人模人人爽人人喊网 | 亚洲免费a | 精品亚洲视频在线 | 精品国产视频在线观看 | 国产精品ⅴa有声小说 | 欧美成人影音 | 在线观看av麻豆 | 日韩免费中文字幕 | 免费一级黄色 | 免费一级片视频 | 91免费试看 | 国产精品福利在线播放 | 国产一级一级国产 | 国产粉嫩在线 | 亚洲视频999 | 免费av大全 | 亚洲精品小视频在线观看 | 国产玖玖在线 | 色视频网站免费观看 | 日日干天夜夜 | 亚洲精品成人网 | 国产成人av一区二区三区在线观看 | 8x成人免费视频 | 国际av在线 | 黄色在线观看免费网站 | 日韩在线电影一区二区 | 免费在线播放视频 | а天堂中文最新一区二区三区 | 成人看片 | 国产专区精品 | 中文字幕一区二区三区久久蜜桃 | 亚洲视频每日更新 | 99热这里只有精品在线观看 | 久久久免费电影 | 欧美性一级观看 | 成人午夜电影免费在线观看 | 日韩特级黄色片 | 国产精品人成电影在线观看 | 久久国产精品久久久 | 在线免费av网站 | 欧美另类老妇 | 啪啪小视频网站 | 玖玖视频精品 | 久草资源在线 | 激情综合网五月 | 久久精品久久久久电影 | 九九精品毛片 | 久久99国产精品自在自在app | 亚洲aⅴ一区二区三区 | 亚洲精品高清视频在线观看 | 久久婷婷五月综合色丁香 | 久久久久在线视频 | 伊人天天狠天天添日日拍 | 91大神一区二区三区 | 欧美综合久久 | 大胆欧美gogo免费视频一二区 | 成人午夜剧场在线观看 | 韩国av电影在线观看 | 免费的黄色av | 免费在线观看视频a | 99国产成+人+综合+亚洲 欧美 | 亚洲精品午夜一区人人爽 | 色五月色开心色婷婷色丁香 | 在线免费黄网站 | 在线免费国产 | 日韩成人中文字幕 | 亚洲精品久久久久久中文传媒 | 久久久免费 | 国产不卡av在线 | 狠狠色伊人亚洲综合网站色 | 四虎永久免费在线观看 | 中文字幕国产亚洲 | 精品国产一区二区三区久久久久久 | 久久高清国产视频 | 天天综合在线观看 | 国产精品 国产精品 | 玖玖精品视频 | 久久国产一区 | 美女视频网站久久 | 国产不卡精品视频 | 69国产盗摄一区二区三区五区 | 午夜美女视频 | 手机在线视频福利 | a级片韩国 | 99精品国产一区二区 | 激情六月婷婷久久 | 亚洲色影爱久久精品 | 在线免费观看黄色小说 | 91麻豆精品国产91久久久久久久久 | 日韩成人中文字幕 | 亚洲资源在线 | 99精品福利 | 黄色在线观看www | 热热热热热色 | 中文字幕在线一区二区三区 | 亚洲激情中文 | 麻豆播放 | 一区二区三区高清 | 欧美日韩国产高清视频 | 成人a在线| 黄色福利视频网站 | 国产精品福利午夜在线观看 | 91最新网址 | 九九九电影免费看 | 久久精品精品电影网 | 国产精品va在线 | 五月婷婷丁香 | 97色资源| 日韩美女一级片 | 五月婷久久 | 干av在线| 日日日天天天 | www日日 | wwwwwww色| 日韩三级视频在线看 | 国产一区二区高清不卡 | 国产在线色站 | 99爱在线观看 | 91精品久久久久久综合乱菊 | 午夜精品一区二区三区在线视频 | 午夜久久视频 | 免费在线观看黄色网 | 91av官网| 国产偷国产偷亚洲清高 | 在线观看的a站 | 亚洲激情六月 | 91亚洲精| 婷婷激情在线观看 | 国产色在线视频 | 在线免费日韩 | 成人资源站| 国产短视频在线播放 | 黄色大片av | 一本大道久久精品懂色aⅴ 五月婷社区 | 久草在线资源免费 | 亚洲免费av网站 | 久久99亚洲精品久久 | 91综合视频在线观看 | 在线观看日韩免费视频 | 在线国产99 | 天天干天天操天天操 | 亚洲女人av | 精品在线免费观看 | 亚洲黄色av | 中文字幕二区在线观看 | 欧美日韩精品在线一区二区 | 日本系列中文字幕 | 国产xvideos免费视频播放 | 91成人免费看片 | 久久成人18免费网站 | 日韩av成人在线观看 | 在线观看中文字幕视频 | 国产美女免费看 | 97在线视频免费看 | 97在线观看免费观看高清 | 日韩精品欧美精品 | 丰满少妇高潮在线观看 | av高清不卡 | 911亚洲精品第一 | 日本精品久久久久久 | 久久综合五月 | 国产成人一区在线 | 在线视频 精品 | 美女网站黄免费 | 久久久久久久久久影视 | 天天干 夜夜操 | 国产不卡视频 | www国产一区| 91成人黄色| 在线免费国产视频 | 久久久国产一区 | 日韩高清在线一区二区三区 | 97热久久免费频精品99 | 久久久久国产精品免费免费搜索 | 久久毛片网站 | 丁香久久激情 | 国产在线黄色 | 国产精品综合久久久久久 | 国产精品一区二区av影院萌芽 | 在线www色| av国产在线观看 | 丝袜足交在线 | 韩国一区二区三区在线观看 | 人人草在线视频 | 手机av电影在线观看 | 亚州精品天堂中文字幕 | 在线高清av| 最近中文字幕大全 | 91亚洲在线 | 日韩网站在线播放 | 超碰人人在线观看 | 蜜臀精品久久久久久蜜臀 | 久久久免费视频播放 | 国产不卡在线视频 | 国产免费影院 | 人人玩人人添人人 | 黄网站色欧美视频 | 激情网五月天 | 日韩在线播放视频 | 久久少妇av| 一本一本久久a久久精品综合小说 | 黄色的视频 | 久久精品久久精品 | 国产美女在线精品免费观看 | 成人va天堂| 久草免费在线视频 | 国产69精品久久app免费版 | 麻豆91小视频 | 91看国产 | 国产护士hd高朝护士1 | 天天插日日操 | 在线观看一二三区 | 国产一区二区午夜 | 日韩特黄av| 天堂麻豆 | 手机在线日韩视频 | 免费日韩一区二区三区 | 日本福利视频在线 | adn—256中文在线观看 | av在线免费在线 | 91视频下载| 成人国产精品免费观看 | 超碰在线最新网址 | 欧美日韩在线观看视频 | 日韩专区av | 国产精品精品国产婷婷这里av | 日韩成人免费在线 | 麻花豆传媒一二三产区 | 亚欧洲精品视频在线观看 | 揉bbb玩bbb少妇bbb | 国产精品爽爽久久久久久蜜臀 | 五月婷婷播播 | 国产福利一区二区在线 | 日韩一区二区三区免费电影 | 99热精品在线 | 青春草免费视频 | 激情五月在线视频 | 久操中文字幕在线观看 | 亚州av一区 | 久草视频资源 | 久久国产电影院 | 91尤物国产尤物福利在线播放 | 久久天天躁夜夜躁狠狠躁2022 | 国产精品一区二区三区99 | 日韩视频免费看 | 国产一级一级国产 | 视频国产在线观看18 | 18国产精品白浆在线观看免费 | 色诱亚洲精品久久久久久 | 欧美日韩99 | 在线亚洲日本 | 五月婷久 | 日韩 在线 | 在线观看黄网站 | 成人一区二区三区在线 | 九九热99视频 | 91成人精品 | 亚洲免费观看在线视频 | 色婷婷av在线 | 九九久久婷婷 | 97精品国自产拍在线观看 | av在线观 | 日日夜夜人人精品 | 又爽又黄又刺激的视频 | 中文字幕在线观 | 亚洲国产剧情av | 成人午夜黄色影院 | 国产精品理论在线观看 | 欧美日韩视频 | 久久人人爽爽人人爽人人片av | 久久视频在线观看免费 | 久久人人爽爽人人爽人人片av | 国产蜜臀av| 毛片888| 伊人久久五月天 | 日本一区二区三区免费看 | 一区二区网 | 久久试看 | 久久综合免费视频影院 | 日韩首页| 黄色小说在线观看视频 | 一区在线免费观看 | 久久99精品热在线观看 | 精品视频www| www夜夜操| 成年人在线免费看片 | 深爱激情综合网 | 成人黄色免费观看 | 日本一区二区三区免费观看 | av+在线播放在线播放 | 免费观看成年人视频 | 婷婷激情综合五月天 | 欧美日韩有码 | 亚洲精品久久久久久中文传媒 | 日韩精品一区在线观看 | 中文字幕一区二区在线播放 | 国产麻豆精品95视频 | 久久伊人八月婷婷综合激情 | 成人资源网 | 日韩三级中文字幕 | 欧美精品v国产精品v日韩精品 | 婷婷日韩 | 精品美女久久久久 | 成人午夜性影院 | 国产伦精品一区二区三区无广告 | 欧美analxxxx | 偷拍区另类综合在线 | 国产精品2018 | 亚洲涩涩涩 | 日韩免费三级 | 久久综合九色综合欧美就去吻 | 手机在线小视频 | 国产五月色婷婷六月丁香视频 | 午夜精品福利影院 | 黄色a视频 | 在线国产激情视频 | 在线免费视频a | 婷婷综合久久 | 国产精品a久久 | av在线在线 | 欧美va电影 | 黄色亚洲片 | 日韩网站在线看片你懂的 | 国产色婷婷精品综合在线手机播放 | 欧美一级久久 | 欧美性爽爽 | 国产免费a | 欧美人操人 | 亚州国产视频 | 麻豆视频在线免费看 | 日韩高清一二区 | 久久综合久久八八 | 久久tv视频 | 热久久免费国产视频 | 欧美视频一区二 | 中文字幕精品一区二区精品 | 日韩最新理论电影 | 国产视频一区二区在线 | 欧美日韩精品在线观看 | 一级片免费在线 | 手机在线看永久av片免费 | 久久综合免费视频 | 日韩黄在线观看 | 日日夜夜网| 久草免费在线视频观看 | 久久免费在线观看视频 | 69视频国产 | 福利在线看片 | 天天插天天干 | 五月婷婷视频在线 | 在线观看日本高清mv视频 | 国产精品一区在线观看 | 欧美日韩亚洲一 | 黄色特级片 | 久久激五月天综合精品 | 亚洲国产精品视频在线观看 | 亚洲精品中文在线资源 | 日韩成人中文字幕 | 日韩毛片精品 | 91视频在线免费 | 三上悠亚一区二区在线观看 | 麻豆一区在线观看 | 欧美精品中文字幕亚洲专区 | 日韩91av | 91看片在线 | 日韩精品五月天 | 麻豆视频网址 | 国产免码va在线观看免费 | 国产黄色成人av | 97超碰人人澡人人爱学生 | 免费色黄 | 久久精品视频免费观看 | 午夜精品中文字幕 | 日韩一区二区免费在线观看 | 精品亚洲国产视频 | 久久精品视频一 | www91在线| 国内久久精品视频 | 久久新 | 欧美精品一区二区在线观看 | 日本性xxx| www.操.com| 99视频免费看 | 草久草久 | 亚洲精品视频网站在线观看 | 在线看av的网址 | 五月婷婷综合在线 | 天天综合成人 | 国产精品9999 | 日韩精品久久一区二区 | 97精品超碰一区二区三区 | 一区二区三区国产欧美 | 国产成人精品一区二区三区在线观看 | 成人黄色一级视频 | 91在线九色 | 亚洲美女精品视频 | 久久99精品久久久久久三级 | 69热国产视频 | 在线观看成人福利 | 国产不卡一区二区视频 | 免费在线观看国产黄 | 999久久精品| 中文字幕第一页在线 | 久草在线最新视频 | 国产亚洲情侣一区二区无 | 国产淫片免费看 | 色综合久久网 | 中文字幕中文字幕在线中文字幕三区 | 外国av网| 成人丝袜| 人人视频网站 | 欧美日本在线视频 | 久久综合狠狠综合久久激情 | 欧美 日韩 国产 成人 在线 | 国语自产偷拍精品视频偷 | 国产精品观看 | 国产91小视频 | 99精品一区 | 日日躁你夜夜躁你av蜜 | 91精品久久久久久综合五月天 | 91精品婷婷国产综合久久蝌蚪 | 黄色三级免费 | 四虎成人精品 | 久久久国际精品 | 在线精品亚洲一区二区 | 免费黄色网址大全 | 欧美综合干| 亚洲伊人av | 亚洲欧美激情精品一区二区 | 西西44人体做爰大胆视频 | 国产成人一二片 | 日韩精品一区二区久久 | 午夜 在线| 四虎成人精品在永久免费 | 欧亚久久 | 日韩午夜精品 | 西西444www高清大胆 | 毛片播放网站 | 亚洲三级黄色 | 色综合在 | 久久99久久99免费视频 | av网站免费在线 | 成人在线免费小视频 | 日韩午夜一级片 | 干干干操操操 | 欧美激情精品久久久久久变态 | www色网站 | 亚洲国产精品久久久久 | 久久久福利视频 | 国产精品九九久久久久久久 | 成 人 a v天堂 | 久久久www| 综合网在线视频 | www.亚洲精品视频 | 成人精品视频久久久久 | av中文字幕在线观看网站 | 国产无遮挡又黄又爽馒头漫画 | av中文字幕剧情 | 激情视频在线观看网址 | 国产一级三级 | 亚洲精品视频免费 | 亚洲精品字幕在线观看 | 久久久精品久久日韩一区综合 | 久久夜夜夜 | 四虎在线免费观看 | 在线视频一区二区 | 亚洲三级黄色 | 国产成人免费高清 | 男女全黄一级一级高潮免费看 | 久久综合婷婷 | 国产免费亚洲高清 | 日韩亚洲在线视频 | 日韩免费视频网站 | 久久久久久久久久久精 | 国产精品久久久久av免费 | 99视频精品免费观看, | 久久精品国产免费看久久精品 | 在线看小早川怜子av | 日韩精品在线免费观看 | 日日夜夜精品免费 | 97超碰中文 | 国产视频一二三 | 久久色亚洲 | 欧美片一区二区三区 | 国产品久精国精产拍 | 久久久久免费网站 | 色欲综合视频天天天 | 亚洲日本精品视频 | 久久精品一区二区三 | 一区二区精品视频 | 欧美激情第十页 | 日韩在线观看电影 | 丁香六月国产 | 婷婷网站天天婷婷网站 | 91九色性视频 | 国内精品一区二区 | 日韩中文在线电影 | 久久久九色精品国产一区二区三区 | 久久综合狠狠综合久久综合88 | 久久久久97国产 | 日韩视频免费看 | 麻豆网站免费观看 | 十八岁免进欧美 | 欧美日韩一区二区视频在线观看 | 肉色欧美久久久久久久免费看 | 99视频在线观看视频 | zzijzzij亚洲成熟少妇 | 日韩一区二区在线免费观看 | 国产三级精品在线 | 亚洲欧洲精品视频 | 99亚洲视频| 伊人天天 | 亚洲视频综合在线 | 国产精品区在线观看 | 香蕉97视频观看在线观看 | 2000xxx影视 | 综合色综合 | 黄色一集片 | 爱爱av在线 | 亚洲九九爱 | 久久99精品久久久久蜜臀 | 色狠狠综合天天综合综合 | 手机看片午夜 | 欧美精品在线观看免费 | 国产91九色视频 | 色九九视频| 99c视频在线| 国产偷v国产偷∨精品视频 在线草 | 日韩羞羞| 亚洲综合在线五月天 | 在线观看网站黄 | 久久av网址 | 久久不射影院 | 国产在线专区 | 国产精品男女 | 草久在线 | 国内精品久久久久久 | 欧美日韩国产三级 | 久久综合九色欧美综合狠狠 | 亚洲精选视频免费看 | 天天干夜夜爽 | 欧美日韩亚洲在线 | 亚洲精品66| 在线播放91 | 午夜视频在线瓜伦 | 国产又粗又猛又爽又黄的视频先 | 国产成人av一区二区三区在线观看 | 日日爱av| 亚洲精品在线免费看 | 午夜精品一区二区三区免费 | 精品日韩视频 | 国产热re99久久6国产精品 | 美女久久| 亚洲一区二区视频在线 | 欧美成人a在线 | 色网站在线看 | 免费污片| 91视视频在线直接观看在线看网页在线看 | 四虎在线观看精品视频 | 欧美在线视频一区二区 | 九九热精品视频在线播放 | 亚洲精品一区二区三区高潮 | av在线免费播放 | 91热这里只有精品 | 欧美一区二区三区在线观看 | av免费观看高清 | 中文字幕日本在线 | 米奇四色影视 | 欧美怡红院 | 国产麻豆精品在线观看 | 日韩欧美在线免费观看 | 成人资源在线 | 狠狠网 | 亚洲激情综合 | 五月婷婷一区 | 亚洲第一成网站 | 亚洲一区二区黄色 | 又污又黄的网站 | 国产精彩视频 | 国产精品video | 久久综合成人网 | 婷婷中文字幕在线观看 | a级片网站 | 久久成人久久 | 丝袜制服综合网 | 日韩爱爱片 | 又黄又爽的视频在线观看网站 | 国产麻豆精品传媒av国产下载 | 色视频成人在线观看免 | 精品在线观看免费 | 日韩av网页 | 夜夜高潮夜夜爽国产伦精品 | 三级午夜片| 日韩av进入 | 日韩区欠美精品av视频 | 日韩在线电影一区 | 欧美亚洲国产一卡 | 国产精品系列在线 | 久久超碰99 | 日本中文字幕电影在线免费观看 | 丁香色天天 | av电影免费 | 日韩成人免费在线 | 日韩欧美在线高清 | 97综合视频 | 最新国产在线观看 | 久久久久久久久久伊人 | 久久中国精品 | 欧美另类z0zx | 精品视频 | 精品理论片 | 中文字幕一区二区三区视频 | 欧美最猛性xxxxx亚洲精品 | 久久 一区 | 亚洲一二三区精品 | 久久理论电影网 | 成人一区影院 | 免费成人在线电影 | 日韩一区二区三区高清在线观看 | 欧美一区二区日韩一区二区 | 成年人在线观看视频免费 | 色吧久久| 免费h漫在线观看 | 亚洲网久久 | 国产网红在线 | 色综合久久久久综合体 | 久久99精品国产一区二区三区 | 免费又黄又爽 | 天堂中文在线播放 | 2019中文最近的2019中文在线 | 男女日麻批 | av黄色影院 | 看片的网址 | 有码中文在线 | 欧美日韩国产一区二区在线观看 | 日本久久免费视频 | 国产黄色在线观看 | 国产成人精品一区二区三区福利 | 精品毛片在线 | 国产精品日韩在线播放 | 美女在线黄 | 成人午夜黄色影院 | 日韩黄色av网站 | 视频 天天草 | av综合在线观看 | 欧美色精品天天在线观看视频 | 91精品国产欧美一区二区成人 | 夜色资源站国产www在线视频 | 色吊丝av中文字幕 | 国产精品久久综合 | 国产一区二区在线免费播放 | 色多多视频在线 | 99视频网站 | 中文字幕亚洲欧美 | 久热只有精品 | 亚洲一区日韩精品 | 日韩av视屏 | 一本之道乱码区 | 波多野结衣最新 | 亚洲精品字幕 | 久久久国内精品 | 婷婷激情五月综合 | 国产成人精品综合久久久久99 | 国产亚洲激情视频在线 | 亚洲国产一区二区精品专区 | 亚洲精品国偷自产在线91正片 | 日本久久精 | 国产剧在线观看片 | 日韩在线播放欧美字幕 | 视频在线在亚洲 | 五月天久久久久久 | 一本到视频在线观看 | 日韩乱理 | 三级黄色在线 | 色五月成人 | 亚洲精品国产精品乱码不99热 | 日韩av网站在线播放 | 欧美另类高清 | 一区二区精品国产 | 欧美一区二区在线免费观看 | 园产精品久久久久久久7电影 | 91桃色在线免费观看 | 亚洲aⅴ在线 | 亚洲免费在线看 | 日韩av成人在线观看 | 欧美日韩视频一区二区三区 | 久久国产精品二国产精品中国洋人 | 在线观看免费日韩 | 久久这里 | 欧美日本啪啪无遮挡网站 | 91精品久久香蕉国产线看观看 | 久久网页 | 亚洲一二三久久 | 九九九热精品免费视频观看网站 | 福利视频一区二区 | 久久久久国产免费免费 | 91香蕉视频污在线 | 免费观看v片在线观看 | 狠狠色丁香婷婷综合视频 | 中文国产字幕在线观看 | 在线视频精品 | 91九色最新地址 | 激情开心色 | 在线视频99 | 国产在线观看中文字幕 | 涩av在线 | h久久| 欧美日韩大片在线观看 | 丁香六月激情婷婷 | 99热这里只有精品在线观看 | 美女久久久久久久久久 | 日韩av综合网站 | 美女视频黄是免费的 | 日韩黄色一级电影 | 日韩欧美99 | 国产一在线精品一区在线观看 | 高清av网站 | 久久久国产精品视频 | 日日夜夜网 | 啪一啪在线 | 91av视屏| 国产视频69 | 韩国精品视频在线观看 | 丰满少妇在线观看 | 性日韩欧美在线视频 | 免费在线观看a v | 亚洲午夜av久久乱码 | 精品国产一区二区三区日日嗨 | 国产亚洲免费观看 | 国产美女精品久久久 | 一级黄色大片 | 激情网站免费观看 | 91精品国产99久久久久 | 久久黄色a级片 | 亚洲精品乱码久久久久久久久久 | 久久久99精品免费观看 | 久久69精品久久久久久久电影好 | 日韩精品在线免费播放 | av网站免费线看精品 | 日韩在线中文字幕 | 亚洲国产美女精品久久久久∴ | 国产精品一区二区中文字幕 | 午夜体验区| 久久婷婷一区二区三区 | 国产精品久久久久av福利动漫 | 午夜av免费观看 | 国产色综合天天综合网 | 欧美日韩在线视频一区二区 | 免费在线观看污 | 亚洲欧洲精品一区二区 | 久久精品8| 亚洲一区视频在线播放 | 国产小视频你懂的在线 | 国产精彩视频一区 | 色综合久久88 | 精品久久久久免费极品大片 | 黄色大片网 | 超碰人人舔 | 国内精品久久久久久久久久 | 欧美做受高潮 | 91人人射 | 久久99国产精品视频 | 久久精品老司机 | 国产一线二线三线性视频 | 日本成人a | 五月花激情 | 日韩三级免费 | 99久久精品一区二区成人 | 黄色资源在线 | 久操97| 在线观看一 | 怡红院av久久久久久久 | 毛片一区二区 | 丁香5月婷婷久久 |