編輯:關於Android編程
通過這片文章可以回答以下兩個問題
1、為啥EventBus的事件處理方法必須申明為Public?但是我用protected也是OK的
2、粘性事件的原理,為啥發送多次Event,只有最新的event能夠得到處理?
vc+88rWloaPG5NbQ1+66y9DEtcTA4M6qRXZlbnRCdXO6zVN1YnNjcmliZXJNZXRob2RGSW5kZXKjrEV2ZW50QnVzzeqzycHLvvi087K/t9ajqNeisuGhoreisryhoru6tOahoreiyeS199PD16Ky4dXft723qLXIo6m1xMLfvK25psTco6xTdWJzY3JpYmVyTWV0aG9kRkluZGVy1PLTw9PasunV0teisuHA4LXEysK8/re9t6iho7jDwODNvEV2ZW50QnVzyc+3vbXEwODW99Kq08PT2s3qs8lFdmVudEJ1c7XE16Ky4bmk1/ejrLb4z8K3vbXEveG5+1Bvc3RlctTy08PT2kV2ZW50QnVztcTKwrz+t6KyvKGjPC9wPg0KPGgyIGlkPQ=="eventbus流程圖">EventBus流程圖
1)EventBus的注冊過程中, 通過反射的方式找到注冊類中所有的事件處理方法(@Subscriber標注的public方法),再將注冊類的信息保存在HashMap中。如果發現注冊類中的某個方法是sticky的,那麼將會直接進入事件發布的流程
2)EventBus的事件發布過程中,不管采用哪一種線程模型,最重都會調用EventBus類中的invokeSubscriber()方法。如果客戶端發送的是一個Sticky事件,EventBus將event事件存入到粘性事件緩存stickyEvents中,然後回到普通事件的處理流程上
getDefault()方法,獲得默認的EventBus實例
//默認情況下,采用單例模式,線程安全。 //也可以不用單例模式,EventBus的構造方法是public的,因此初始化自己的EventBus對象 public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
register()方法,訂閱者注冊
//subscriber就是訂閱發布 模式中的訂閱著,如我們的Activity public void register(Object subscriber) { Class subscriberClass = subscriber.getClass();//獲取訂閱者的Class類對象 ListsubscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//獲取該類中的事件方法(@subscribe標簽),SubscriberMethod類包含了注冊者的類、方法、sticky、線程模式等信息 synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod);//緩存注冊者信息 } } }
findSubscriberMethods()方法,獲得訂閱者中@Subscribe標識的方法
ListfindSubscriberMethods(Class subscriberClass) { List subscriberMethods = METHOD_CACHE.get(subscriberClass);//從緩存中找 if (subscriberMethods != null) { return subscriberMethods;//緩存命中,直接返回 } //ignoreGeneratedIndex默認情況為false,但都會走到findUsingReflectionInSingleClass方法中,通過反射來找到@Subscribe標識的方法 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; } } //通過反射來處理,找到訂閱者中@Subscribe標識的方法 private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { // 獲取注冊類的所有申明方法(非繼承方法),該方法的效率比getMehtods()高 methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; } for (Method method : methods) { int modifiers = method.getModifiers();//方法的修飾符:public //找到public修飾的方法,這裡奇怪的是,protected的方法通過反射得到的方法修飾符也是public,這就是為什麼protected修飾的方法也能使用的原因!! if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { //找到參數個數為1的方法 Class[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { //找到注解@Subscribe標識的方法 Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { Class eventType = parameterTypes[0];//獲取參數 if (findState.checkAdd(method, eventType)) { ThreadMode threadMode = subscribeAnnotation.threadMode();//從注解獲取線程模型 findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { 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)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }
subscribe()方法,在找到注冊類的方法後,就需要對這些方法也注冊,存入緩存中
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class eventType = subscriberMethod.eventType;//消息事件的類型 Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//Subscription類封裝了注冊者和它的一個方法 CopyOnWriteArrayListsubscriptions = 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; } } //向緩存中添加subscriber所對應的Event。感覺typesBySubscriber沒啥用? List > subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); //注冊粘性事件 if (subscriberMethod.sticky) { if (eventInheritance) { // 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 ). Set , Object>> entries = stickyEvents.entrySet(); for (Map.Entry , Object> entry : entries) { Class candidateEventType = entry.getKey(); if (eventType.isAssignableFrom(candidateEventType)) { Object stickyEvent = entry.getValue(); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } } else { Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent);//該方法將會直接跳轉到事件發布歷程中執行 } } }
post()方法,發布者發布消息事件
//currentPostingThreadState是一個ThredLocal變量,線程內部共享數據,線程間安全 private final ThreadLocalcurrentPostingThreadState = new ThreadLocal () { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } }; //發布event粘性事件 public void postSticky(Object event) { synchronized (stickyEvents) { //stickyEvents是ConcurrentHashMap,每次往map中put鍵值對,會覆蓋具有相同event.getClass()的值,因此導致即使發布多次粘性事件,也只會處理最新的那一個 //換句話即:同一個event類,在緩存中只會保存一個粘性事件! stickyEvents.put(event.getClass(), event); } post(event); } //發布event事件 public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); List
AsyncPoster類,實現了Runnable接口
class AsyncPoster implements Runnable { private final PendingPostQueue queue; private final EventBus eventBus; AsyncPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); queue.enqueue(pendingPost);//加入隊列中 eventBus.getExecutorService().execute(this);//調用線程池執行,並發執行 } @Override public void run() { PendingPost pendingPost = queue.poll(); if(pendingPost == null) { throw new IllegalStateException("No pending post available"); } eventBus.invokeSubscriber(pendingPost);//調用EventBus的反射方法 } }
BackgroundPoster類,雖然也實現了Runnable接口,雖然也在子線程中執行EventBus的反射回調方法。但是與AsyncPoster類不同的是:
1)AsyncPoster類每次任務都會新建一個線程,並發執行隊列中的任務
2)而BackgroundPoster類只會新建一個子線程,隊列中的任務,只會順序執行。
final class BackgroundPoster implements Runnable { private final PendingPostQueue queue; private final EventBus eventBus; private volatile boolean executorRunning; BackgroundPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { queue.enqueue(pendingPost); if (!executorRunning) { executorRunning = true; eventBus.getExecutorService().execute(this); } } } @Override public void run() { try { try { while (true) { PendingPost pendingPost = queue.poll(1000); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = queue.poll(); if (pendingPost == null) { executorRunning = false; return; } } } eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { Log.w("Event", Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; } } }
mainThreadPoster是HandlerPoster變量,他繼承Handler,不難猜出,他通過Handler+Looper機制,來實現主線程調用
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);//綁定主線程的Looper final class HandlerPoster extends Handler { private final PendingPostQueue queue; private final int maxMillisInsideHandleMessage; private final EventBus eventBus; private boolean handlerActive; HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { super(looper);//綁定主線程的Looper this.eventBus = eventBus; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; queue = new PendingPostQueue(); } 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"); } } } } //處理event事件,調用EventBus的invokeSubscriber反射回調 public void handleMessage(Message msg) { boolean rescheduled = false; try { long started = SystemClock.uptimeMillis(); while (true) { PendingPost pendingPost = queue.poll(); if (pendingPost == null) { synchronized (this) { // 雙重判0,線程安全 pendingPost = queue.poll(); if (pendingPost == null) { handlerActive = false; return; } } } eventBus.invokeSubscriber(pendingPost);//調用EventBus的反射方法 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; } } }
關於Layout_width/height引發的寬高思考方式一: 結果不符合預期。運行結果: 方式二:
本示例演示在Android中實現圖片左右滑動效果。關於滑動效果,在Android中用得比較多,本示例實現的滑動效果是使用ViewFlipper來實現的,當然也可以使用其它
EditView類繼承自TextView類,EditView與TextView最大的不同就是用戶可以對EditView控件進行編輯,
首先上效果圖 第一張圖是進入該界面的效果,頂部是一個viewpager,下面每個塊都是自定義的view HomeButton,第二張圖是點擊右邊第一個方塊的效果,點擊時方