EventBus의 간단한 에디션
사실 이벤트버스의 원리는 어렵지 않다. 몇 개의 그룹을 유지한 다음에 대응하는 키에 따라 대응하는 등록 대상을 찾아 방사능을 통해 대응하는 방법을 호출하는 것이다.
EventBus3.0 이전과 이후는 비교적 큰 차이가 있는데 가장 큰 차이는 3.0 이후 apt 재컴파일 기간에 인용 대상을 생성하여 어느 정도 성능을 향상시켰다.
가장 간편한 사용
//
EventBus.getDefault().register(this);
//
@Subscribe
public void event(BaseEventBusBeaan message) {
LogUtils.d("EventBusActivity event");
}
//
EventBus.getDefault().post(new BaseEventBusBeaan("123", new Bundle()));
//
EventBus.getDefault().unregister(this);
post 프로세스
우선 우리는 우리의 수요를 정리해야 한다. 우리가 필요로 하는 것은
post
한 대상이 나갈 때 모든 등록 감청 대상의 클래스가 이 통지를 받을 수 있기 때문에 여기에 데이터를 저장할 수 있는 그룹이 필요하다.//post key, Subscription list value
private Map, CopyOnWriteArrayList> subscriptionsByEventType;
// Subscription
public class Subscription {
final Object subscriber; //activity fragment
final SubscriberMethod subscriberMethod;
public Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
}
}
public class SubscriberMethod {
private String methodName; //
private Method method; // ,
private ThreadMode threadMode; //
private Class> eventType; // Class, :UserInfo.class
}
subscriptionsByEventType
가 생기면 우리는 post()
의 발송된 사건에 따라 모든 등록자를 찾아서 다시 list
를 훑어보고 하나하나 반사할 수 있다.public void post(Object event) {
postSingleEventForEventType(event, event.getClass());
}
// ,
private void postSingleEventForEventType(Object event, Class> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
invokeSubscriber(subscription, event);
}
}
}
//
private void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.getMethod().invoke(subscription.subscriber, event);
} catch (Exception e) {
e.printStackTrace();
}
}
상술한 것은 바로 간략판
post
과정이다.Register 프로세스
상술한
post
에는 아직 중요한 부분이 하나 있다. 바로 subscriptionsByEventType
데이터의 출처이다. 우리는 자연스럽게 register
과정이라고 생각해야 한다.다시
subscriptionsByEventType
의 키와value를 살펴보면 이 값들은 대부분 아래의 함수에서 얻을 수 있다는 것을 알 수 있다.@Subscribe
public void event(BaseEventBusBeaan message) {
LogUtils.d("EventBusActivity event");
}
그래서 우리는 클래스의 모든 방법을 훑어보고
@Subscribe
주석된 함수를 찾아서 저장해야 한다.이것은 apt 방안으로 컴파일 과정에서 모든 종류를 두루 훑어보고
@Subscribe
에 주석된 함수를 찾아 일정한 양식에 따라 저장하면 다음과 같은 종류가 생성됩니다.// ,
// @Subscribe SUBSCRIBER_INDEX 。
//key , MainActivity,value , 。
public final class MyEventBusIndex implements SubscriberInfoIndex {
private static final Map SUBSCRIBER_INDEX;
static {
SUBSCRIBER_INDEX = new HashMap();
putIndex(new SimpleSubscriberInfo(EventBusActivity2.class,
new SubscriberMethod[] {
new SubscriberMethod(EventBusActivity2.class, "event", BaseEventBusBeaan.class, ThreadMode.POSTING, 0, false),
new SubscriberMethod(EventBusActivity2.class, "sticky", UserInfo.class, ThreadMode.POSTING, 2, true),
new SubscriberMethod(EventBusActivity2.class, "sticky2", UserInfo.class, ThreadMode.POSTING, 2, true)}
));
}
private static void putIndex(SubscriberInfo info) {
SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
}
@Override
public SubscriberInfo getSubscriberInfo(Class subscriberClass) {
return SUBSCRIBER_INDEX.get(subscriberClass);
}
}
MyEventBusIndex
가 생기면 register
절차를 시작합니다.public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
List subscriberMethods = findSubscriberMethods(subscriberClass);
// subscriptionsByEventType ,
for (SubscriberMethod method : subscriberMethods) {
subscribe(subscriber, method);
}
}
//1. subscriberClass methodBySubscriber
private List findSubscriberMethods(Class> subscriberClass) {
List subscriberMethods = methodBySubscriber.get(subscriberClass);
if (subscriberMethods != null) return subscriberMethods;
subscriberMethods = findByAPT(subscriberClass);
if (subscriberMethods != null) {
methodBySubscriber.put(subscriberClass, subscriberMethods);
}
return subscriberMethods;
}
//2. subscriberInfoIndex ,subscriberInfoIndex MyEventBusIndex
private List findByAPT(Class> subscriberClass) {
if (subscriberInfoIndex == null) {
throw new RuntimeException(" ");
}
SubscriberInfo subscriberInfo = subscriberInfoIndex.getSubscriberInfo(subscriberClass);
if (subscriberInfo != null) return Arrays.asList(subscriberInfo.getSubscriberMethods());
return null;
}
이어서 옮겨다니기 시작
subscriberMethods
(구독자마다 한 가지 방법만 추가된 것은 아니기 때문@Subscribe
주석)for (SubscriberMethod method : subscriberMethods) {
subscribe(subscriber, method);
}
// post subscriptionsByEventType 。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.getEventType();
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
}
Subscription subscription = new Subscription(subscriber, subscriberMethod);
subscriptions.add(i, subscription);
// ,unregister
List> subscribeEvents = typeBySubscriber.get(subscriber);
if (subscribeEvents == null) {
subscribeEvents = new ArrayList<>();
typeBySubscriber.put(subscriber, subscribeEvents);
}
subscribeEvents.add(eventType);
}
여기까지 왔는데 사실 간단한 절차 하나가 이미 통했다.
대략적인 절차를 총결해 보다
@Subscribe
에 주석된 모든 함수를 MyEventBusIndex
대상에 추가합니다.register
과정에서 생성된 데이터subscriptionsByEventType
.post
과정에서 subscriptionsByEventType
데이터로 대응하는 함수를 찾은 다음에 반사하는 방식으로 호출한다.우선 순위 문제
이 문제도 간단하다. 데이터를 삽입할 때 우선순위를 판단하면 된다.
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.getEventType();
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
}
Subscription subscription = new Subscription(subscriber, subscriberMethod);
//
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.getPriority() > subscriptions.get(i).subscriberMethod.getPriority()) {
if (!subscriptions.contains(subscription)) subscriptions.add(i, subscription);
break;
}
}
// ,unregister
List> subscribeEvents = typeBySubscriber.get(subscriber);
if (subscribeEvents == null) {
subscribeEvents = new ArrayList<>();
typeBySubscriber.put(subscriber, subscribeEvents);
}
subscribeEvents.add(eventType);
}
점성 이벤트
일반 이벤트는 먼저 등록하고 발송합니다.점성 이벤트는 반대로 먼저 보내고 나중에 등록한다.
우리는 단지 순서를 바꾸기만 하면 된다.발송할 때 이벤트를 저장한 다음
register
할 때 적당한 이벤트가 있는지 확인하세요public void postSticky(Object event) {
stickyEvents.put(event.getClass(), event);
}
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
....
//
sticky(subscriberMethod, eventType, subscription);
}
private void sticky(SubscriberMethod subscriberMethod, Class> eventType, Subscription subscription) {
if (subscriberMethod.isSticky()) {
Object event = stickyEvents.get(eventType);
if (event != null) {
postToSubscription(subscription, event);
}
}
}
마지막으로
postToSubscription
코드를 추가합니다.private void postToSubscription(final Subscription subscription, final Object event) {
switch (subscription.subscriberMethod.getThreadMode()) {
case POSTING: // 、
invokeSubscriber(subscription, event);
break;
case MAIN:
//
if (Looper.myLooper() == Looper.getMainLooper()) {
invokeSubscriber(subscription, event);
} else {
//
handler.post(new Runnable() {
@Override
public void run() {
invokeSubscriber(subscription, event);
}
});
}
break;
case ASYNC:
//
if (Looper.myLooper() == Looper.getMainLooper()) {
executorService.execute(new Runnable() {
@Override
public void run() {
invokeSubscriber(subscription, event);
}
});
} else {
invokeSubscriber(subscription, event);
}
break;
}
}
private void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.getMethod().invoke(subscription.subscriber, event);
} catch (Exception e) {
e.printStackTrace();
}
}
클릭하여 소스 코드 보기
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.