It should be difficult to write an eventBus framework intuitively. Today, I learned from some materials and found that it is not difficult to implement a simple eventBus framework. When you register with one interface and send messages to another interface, the registered interface can receive the messages and process them. Implement an Eventbus step by step
One. Look at simple usage;
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(r.layout.activity_main) // Register eventbus.getInstance ().register(this)} // Accept messages via annotations. @subscribe (threadMode = threadmode.main) fun getMessage(s: String) {log.d () {Subscribe(threadMode = threadmode.main) fun getMessage(s: String) {log.d ()"Receiving thread"."" + Thread.currentThread().name)
Toast.makeText(this, s, Toast.LENGTH_SHORT).show()
}
override fun onDestroy() {
super.onDestroy()
EventBus.getInstance().unRegister(this)
}
}
Copy the code
Two. Evevtbus principle analysis;
- 1. First, the registration process. Register to pass in the class file of the current class.
- 2. With the class file, you can find out which methods are marked with the specified annotation.
- 3. Store the method (parameter type, thread type, method body) in a container.
- 4. Other interfaces send messages to traverse the container to find the method that matches the parameter type in the container.
- 5. Execute the method in the specified thread.
Three. Handwriting Evevtbus frame;
Write an Evevtbus singleton. There are registration, logout methods.
public class EventBus {
private EventBus() {
}
private static EventBus instance;
public static EventBus getInstance() {
if (instance == null) {
instance = new EventBus();
}
returninstance; Public void unRegister(Object Object) {} public void unRegister(Object Object) {}Copy the code
Enumeration class for thread definition,
Public enum ThreadMode {/** * callback events in the MAIN thread */ MAIN, /** * callback events in the child thread */ BACKGROUND, /** * callback events in the default thread */ POSTING}Copy the code
3. Custom annotation Subscribe,
@target (elementtype.method) // Annotations annotations in methods @Retention(retentionPolicy.runtime) // annotations work at RUNTIME. Java -->.class -->.dex public @interface Subscribe { ThreadMode threadMode() default ThreadMode.POSTING; }Copy the code
4. Package method body
The container contains annotation annotation methods. So encapsulate the method body. The following;
Public class MethodManager {/** ThreadMode ThreadMode; /** Method */ Method; /** formal argument */ Class<? >type; public MethodManager(ThreadMode threadMode, Method method, Class<? >type) {
this.threadMode = threadMode;
this.method = method;
this.type = type;
}
public ThreadMode getThreadMode() {
return threadMode;
}
public void setThreadMode(ThreadMode threadMode) {
this.threadMode = threadMode;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) { this.method = method; } public Class<? >getType() {
return type;
}
public void setType(Class<Object> type) {
this.type = type; }}Copy the code
5. Registration process and sending messages
An interface registration process j is to find the method of marking through annotations, stored in a set, because there are many interfaces to register, so use map container to store the interface corresponding to. Key, value corresponding to the set of interface marking methods. Sending a message is simply walking through the set to find the appropriate method. And then execute it
Public class EventBus {/** * List<MethodManager>> Map; ExecutorService executorService; Handler mhander = new Handler(Looper.getMainLooper()); // Get the main thread hander privateEventBus() {
map = new HashMap<>();
executorService = Executors.newCachedThreadPool();
}
private static EventBus instance;
public static EventBus getInstance() {
if (instance == null) {
instance = new EventBus();
}
returninstance; Public void register(object object) {List<MethodManager> methodManagers = map.get(object);if(methodManagers == null) { findObject(object); } } private void findObject(Object object) { Class<? > aClass = object.getClass(); Method[] declaredMethods = aClass.getDeclaredMethods(); List<MethodManager> list = new ArrayList<>();for (Method declaredMethod : declaredMethods) {
Subscribe annotation = declaredMethod.getAnnotation(Subscribe.class);
if (annotation == null) {
continue; } ThreadMode threadMode = annotation.threadMode(); // The thread flag Class<? >[] parameterTypes = declaredMethod.getParameterTypes();if (parameterTypes == null || parameterTypes.length > 1) {
continue; } Class<? > parameterType = parameterTypes[0]; MethodManager methodManager = new MethodManager(threadMode, declaredMethod, parameterType); list.add(methodManager); } map.put(object, list); Public void post(final Object Object) {Set<Object> objects = map.keyset (); Iterator<Object> iterator = objects.iterator();while (iterator.hasNext()) {
final Object next = iterator.next();
List<MethodManager> list = map.get(next);
for(Final MethodManager MethodManager: list) {// Compares the message type of the sender to that of the receiverif(methodManager.getType().isAssignableFrom(object.getClass())) { ThreadMode threadMode = methodManager.getThreadMode(); invok(next, object, methodManager.getMethod()); ** @param next * @param object * @param method */ private void invok(object next, Object object, Method method) { try { method.invoke(next, object); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public void unRegister(Object object) {if(map.get(object) ! = null) { map.remove(object); }}}Copy the code
6. Thread switching process
Thread switching, in fact, is the execution of the method, determine which thread to execute, to switch. Switching threads is as follows:
if (methodManager.getType().isAssignableFrom(object.getClass())) {
ThreadMode threadMode = methodManager.getThreadMode();
if(threadMode == threadmode.main) {// Execute methods in the MAIN threadif (Looper.myLooper() == Looper.getMainLooper()) {
invok(next, object, methodManager.getMethod());
} else {
mhander.post(new Runnable() {
@Override
public void run() { invok(next, object, methodManager.getMethod()); }}); }}else if(threadMode == threadmode.background) {// Execute method in child threadif (Looper.myLooper() == Looper.getMainLooper()) {
executorService.execute(new Runnable() {
@Override
public void run() { invok(next, object, methodManager.getMethod()); }}); }else{ invok(next, object, methodManager.getMethod()); }}else if(threadMode == ThreadMode.POSTING) { invok(next, object, methodManager.getMethod()); }}Copy the code
Seven. Finish.
This is the end of the simple Eventbus framework. The principle and implementation are not complicated. Another problem is that in multiple processes, the handwritten EventBus is actually invalid because singletons can’t boast about the process. If you want to brag about progress and send a message, look into that next time.