EventBus原理解析和手写(一)
程序员文章站
2022-04-02 18:13:18
...
先在android studio添加引用:
implementation 'org.greenrobot:eventbus:3.1.1'
EventBus常规用法:
FirstActivity的xml布局和代码
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="First Activty"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="跳转"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
</android.support.constraint.ConstraintLayout>
public class FirstActivity extends AppCompatActivity {
private static final String TAG = "FirstActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
EventBus.getDefault().register(this);
}
public void onClick(View view) {
startActivity(new Intent(this, SecondActivity.class));
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Log.e(TAG, getClass().getSimpleName() + "接收到的信息是:" + event.getMsg());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
SecondActivity的xml布局和代码
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Second Activity!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="sendMessage"
android:text="EventBus"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
</android.support.constraint.ConstraintLayout>
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
public void sendMessage(View view) {
EventBus.getDefault().post(new MessageEvent(getClass().getSimpleName() + "发出消息"));
}
}
输出结果:
现在我们来尝试编写一下eventbus框架
1、我们先注释掉eventbus引用
同步结果FristActivity和SecondActivity代码如下:
很显然,我们要通过四个类实现EventBus
1、创建线程模式
2、创建注解
3、封装方法类
4、"存储"方法,并通过反射调用
步骤一:先创建EventBus类
很显然,从上面用法看出,EventBus.getDefault()是个单例模式,开始编写EventBus类
public class EventBus {
private static volatile EventBus instance;
private EventBus() {
}
public static EventBus getDefault() {
if (instance == null) {
synchronized (EventBus.class) {
if (instance == null) {
instance = new EventBus();
}
}
}
return instance;
}
}
创建线程模式:
public enum ThreadMode {
POSTING,
MAIN,
MAIN_ORDERED,
BACKGROUND,
ASYNC
}
创建注解类:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.MAIN;
}
现在来封装方法
public class EventBus {
private static volatile EventBus instance;
private EventBus() {
}
public static EventBus getDefault() {
if (instance == null) {
synchronized (EventBus.class) {
if (instance == null) {
instance = new EventBus();
}
}
}
return instance;
}
public void register(Object object) {
}
}
现在我们来理一下思路:因为有可能Activity和Fragment或者说其他类,有可能会有多个接收方法,如
EventBus发出消息,可能也有多个类都接收,所以显然我们需要定义一个map类,来储存哪个类有哪几个方法是需要接收信息
public class EventBus {
private Map<Object, List<MethodManager>> registerMap;//key用来存储是哪个类,value是该类下的所有接收方法
private static volatile EventBus instance;
private EventBus() {
registerMap = new HashMap<>();
}
public static EventBus getDefault() {
if (instance == null) {
synchronized (EventBus.class) {
if (instance == null) {
instance = new EventBus();
}
}
}
return instance;
}
public void register(Object object) {
}
}
public class MethodManager {
private Class<?> type;//参数类型
private ThreadMode threadMode;//线程模式
private Method method;
public MethodManager(Class<?> type, ThreadMode threadMode, Method method) {
this.type = type;
this.threadMode = threadMode;
this.method = method;
}
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
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;
}
}
我们再来分析一下,接收的方法注解类一定是我们自定义的,且方法的参数是有且只有一个,返回值为void
public class EventBus {
private Map<Object, List<MethodManager>> registerMap;//key用来存储是哪个类,value是该类下的所有接收方法
private static volatile EventBus instance;
private EventBus() {
registerMap = new HashMap<>();
}
public static EventBus getDefault() {
if (instance == null) {
synchronized (EventBus.class) {
if (instance == null) {
instance = new EventBus();
}
}
}
return instance;
}
public void register(Object object) {
List<MethodManager> methodList = registerMap.get(object);
if (methodList == null) {
methodList = findAnotationMethod(object);
registerMap.put(object, methodList);
}
}
private List<MethodManager> findAnotationMethod(Object object) {
List<MethodManager> methodList = new ArrayList<>();
Class<?> clazz = object.getClass();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
Subscribe subscribe = method.getAnnotation(Subscribe.class);
if (subscribe == null) {
continue;
}
//特性1:是无返回值的
Type returnType = method.getGenericReturnType();
if (!"void".equals(returnType.toString())) {
throw new RuntimeException(method.getName() + "方法返回值必须是void");
}
//特性二:方法参数有且只有一个
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) {
throw new RuntimeException(method.getName() + "方法参数有且只有一个");
}
//完全符合了要求
MethodManager methodManager = new MethodManager(parameterTypes[0], subscribe.threadMode(), method);
methodList.add(methodManager);
}
return methodList;
}
/**
* 发送消息
*
* @param setter 方法参数
*/
public void post(Object setter) {
Set<Object> set = registerMap.keySet();
for (Object key : set) {
//遍历哪些类中的方法接收的参数类型符合,发送者。
List<MethodManager> methodList = registerMap.get(key);
for (MethodManager methodManager : methodList) {
if (methodManager.getType().isAssignableFrom(setter.getClass())) {
try {
methodManager.getMethod().invoke(key, setter);//方法调用
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
/**
* 接收类
*
* @param object 接受者
*/
public void unregister(Object object) {
if (registerMap.get(object) != null) {
registerMap.remove(object);
}
}
}
运行结果:
上一篇: linux如何查找文件位置
推荐阅读
-
Spring MVC源码(三) ----- @RequestBody和@ResponseBody原理解析
-
解析:微商难道和微搜索一样是伪命题吗
-
利用递归,反射,注解等,手写Spring Ioc和Di 底层(分分钟喷倒面试官)了解一下
-
Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?
-
Python startswith()和endswith() 方法原理解析
-
Docker 系列一(概念原理和安装).
-
Mybaits 源码解析 (九)----- 全网最详细,没有之一:一级缓存和二级缓存源码分析
-
通过实例解析JMM和Volatile底层原理
-
HashMap原理(一) 概念和底层架构
-
SpringMVC-简介和执行原理分析(一)