Android Java 实现事件总线

发布于:2025-04-05 ⋅ 阅读:(23) ⋅ 点赞:(0)

Android Java 实现事件总线

事件总线(Event Bus)是一种在 Android 开发中常用的组件间通信机制,它可以实现组件间的解耦通信。以下是几种在 Android Java 项目中实现事件总线的方式:

1. 使用第三方库(推荐)

GreenRobot EventBus

添加依赖

implementation 'org.greenrobot:eventbus:3.3.1'

基本使用

  1. 定义事件类:
public class MessageEvent {
    public final String message;
    
    public MessageEvent(String message) {
        this.message = message;
    }
}
  1. 注册/注销订阅者(通常在 Activity/Fragment 中):
@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    super.onStop();
    EventBus.getDefault().unregister(this);
}
  1. 声明订阅方法:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
    Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show();
}
  1. 发布事件:
EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));

2. 自定义简单事件总线

实现代码

import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class SimpleEventBus {
    private static volatile SimpleEventBus instance;
    private final Map<Class<?>, List<Subscriber>> subscribersMap = new HashMap<>();
    private final Executor executor = Executors.newCachedThreadPool();

    public static SimpleEventBus getDefault() {
        if (instance == null) {
            synchronized (SimpleEventBus.class) {
                if (instance == null) {
                    instance = new SimpleEventBus();
                }
            }
        }
        return instance;
    }

    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        Method[] methods = subscriberClass.getDeclaredMethods();
        
        for (Method method : methods) {
            if (method.isAnnotationPresent(Subscribe.class)) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length != 1) {
                    throw new IllegalArgumentException("Subscribe method must have exactly 1 parameter");
                }
                
                Class<?> eventType = parameterTypes[0];
                Subscriber subscriberWrapper = new Subscriber(new WeakReference<>(subscriber), method);
                
                synchronized (this) {
                    List<Subscriber> subscribers = subscribersMap.get(eventType);
                    if (subscribers == null) {
                        subscribers = new ArrayList<>();
                        subscribersMap.put(eventType, subscribers);
                    }
                    subscribers.add(subscriberWrapper);
                }
            }
        }
    }

    public void unregister(Object subscriber) {
        synchronized (this) {
            for (List<Subscriber> subscribers : subscribersMap.values()) {
                for (int i = subscribers.size() - 1; i >= 0; i--) {
                    Subscriber subscriberWrapper = subscribers.get(i);
                    Object target = subscriberWrapper.reference.get();
                    if (target == null || target == subscriber) {
                        subscribers.remove(i);
                    }
                }
            }
        }
    }

    public void post(Object event) {
        Class<?> eventClass = event.getClass();
        List<Subscriber> subscribers;
        
        synchronized (this) {
            subscribers = subscribersMap.get(eventClass);
        }
        
        if (subscribers != null && !subscribers.isEmpty()) {
            for (Subscriber subscriber : subscribers) {
                executor.execute(() -> subscriber.invoke(event));
            }
        }
    }

    private static class Subscriber {
        private final WeakReference<Object> reference;
        private final Method method;
        private final ThreadMode threadMode;

        Subscriber(WeakReference<Object> reference, Method method) {
            this.reference = reference;
            this.method = method;
            this.method.setAccessible(true);
            Subscribe annotation = method.getAnnotation(Subscribe.class);
            this.threadMode = annotation.threadMode();
        }

        void invoke(Object event) {
            Object target = reference.get();
            if (target == null) return;
            
            try {
                if (threadMode == ThreadMode.MAIN) {
                    new Handler(Looper.getMainLooper()).post(() -> {
                        try {
                            method.invoke(target, event);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
                } else {
                    method.invoke(target, event);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public @interface Subscribe {
        ThreadMode threadMode() default ThreadMode.POSTING;
    }

    public enum ThreadMode {
        POSTING, // 与发布者在同一线程
        MAIN    // 主线程
    }
}

使用示例

  1. 定义事件:
public class CustomEvent {
    public String data;
    
    public CustomEvent(String data) {
        this.data = data;
    }
}
  1. 注册和订阅:
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        SimpleEventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        SimpleEventBus.getDefault().unregister(this);
    }

    @SimpleEventBus.Subscribe(threadMode = SimpleEventBus.ThreadMode.MAIN)
    public void onCustomEvent(CustomEvent event) {
        Toast.makeText(this, event.data, Toast.LENGTH_SHORT).show();
    }
}
  1. 发布事件:
SimpleEventBus.getDefault().post(new CustomEvent("Hello from SimpleEventBus!"));

网站公告

今日签到

点亮在社区的每一天
去签到