EventBus的使用以及优化

一、作用和特点

  • 作用:在组件 / 线程间通信的场景中,将数据或事件传递给对应的订阅者。

  • 特点:在 Android 组件 / 线程间通信的应用场景中,EventBus 比传统的接口监听、Handler、Executors、LocalBroadcastManager 更简洁可靠,具体描述如下:

    • 使用事件总线框架,实现事件发布者与订阅者松耦合;

    • 提供了透明线程间通信,隐藏了发布线程与订阅线程间的线程切换。

二、关键角色

  1. Event:事件,它可以是任意类型(需定义)。

  2. Subscriber:事件订阅者,事件处理的方法名可自定义,不过需要加上注解@subscribe,并且可指定线程模型和优先级,默认是POSTING

  3. Publisher:事件的发布者,可以在任意线程里发布事件。一般情况下,使用EventBus.getDefault()就可以得到一个EventBus对象,然后再调用post(Object)方法即可。

三、 事件订阅者

3.1、注册与注销EventBus

在发布事件之前,需要先 注册订阅者。而在订阅者生命周期结束时,需要 注销订阅者。注册与注销应保持在对称的生命周期。一般选择在Activity的onCreate()方法里去注册EventBus,在onDestory()方法里,去解除注册【EventBus持有订阅者的强引用,如果在订阅者被销毁时,没有注销,会导致内存泄漏】。

//注册
if(!EventBus.getDefault().isRegister(this)){
    EventBus.getDefault().register(this);
}

//注销
if(EventBus.getDefault().isRegister(this)){
    EventBus.getDefault().unregister(this);
}

3.2、四种线程模型

设置方式:@Subscribe(threadMode = ThreadMode.MAIN)

  1. ThreadMode.POSTING:默认模式,订阅者发布的事件将会在所在的线程调用。时间的传递是同步的,一旦发布事件,所有对该模式的订阅事件都会执行。这种线程模式意味着最少的性能开销,因为它避免了线程的切换。因此,对于不要求是主线程并且耗时很短的简单任务推荐使用该模式。

  2. ThreadMode.MAIN:订阅方法在主线程(UI)调用 ,因此可以直接更新 UI ,如果发布事件的线程是主线程,那么该模式的订阅者方法将被直接调用。

  3. ThreadMode.MAIN_ORDERED:订阅方法在主线程(UI)调用,因此可以直接更新UI,事件将先进入队列然后才发送给订阅者,所以发布事件的调用将立即返回。这使得事件的处理保持严格的串行顺序。

  4. ThreadMode.BACKGROUND:订阅者方法将在后台线程中被调用,如果发布事件的线程不是主线程,那么订阅者方法将会直接在该线程被调用。如果是主线程,那么将会使用一个单独的后台线程,该线程将按顺序发送所有的事件。

  5. ThreadMode.ASYNC:订阅者方法将在一个单独的线程中被调用,发布事件的调用者将立即返回。如果订阅者方法的执行需要一些时间,例如网络访问,那么就应该使用该模式。避免触发大量的长时间运行的订阅者方法,以限制并发线程的数量。EventBus使用了一个线程池来有效地重用已经完成调用订阅者方法的线程。

注意:使用【1.2.3.4】模式的订阅者方法必须快速返回,以避免阻塞主线程。即订阅者方法执行需要耗时时,需选择【5】线程模式。【1.2.3】使用不当会导致丢帧,【4】使用不当会导致队首阻塞,【5】使用不当会导致内存抖动。

3.3、事件类型

设置方式:@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)

1、基础事件(sticky = false,默认

只有注册了,订阅者才能将接收到事件

2、粘性事件(sticky = true

事件只要发送了,无论是在发送前注册还是发送后注册,订阅者都能收到事件,这就是粘性事件。

3.4、事件优先级

设置方式:@Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 1)

用来指定订阅方法的优先级,是一个整数类型的值,默认是0,值越大表示优先级越大。在同一传递线程(ThreadMode)中,较高优先级的订户将在优先级较低的其他订户之前接收事件。优先级不会影响具有不同ThreadModes的订阅者的传递顺序!

需要注意

  1. 只有当两个订阅方法使用相同的ThreadMode参数的时候,它们的优先级才会与priority指定的值一致;

  2. 只有当某个订阅方法的ThreadMode参数为POSTING的时候,它才能停止该事件的继续分发。

      取消事件传递:EventBus.getDefault().cancelEventDelivery(event) ;

四、编译时索引

默认情况下,EventBus 查找订阅者方法时采用的是反射,订阅者索引可以加速订阅者的注册,是一个可选的优化。其原理是:使用 EventBus 的注解处理器在应用构建期间创建订阅者索引类,该类包含了订阅者和订阅者方法的相关信息。EventBus 官方推荐在 Android 中使用订阅者索引以获得最佳的性能。要开启订阅者索引的生成,你需要在构建脚本中使用annotationProcessor属性将EventBus的注解处理器添加到应用的构建中,还要设置一个eventBusIndex参数来指定要生成的订阅者索引的完全限定类名。

索引优化就是索引优化,它有两种实现方式:手动设置索引和自动设置索引。自动设置索引其实才是使用APT技术实现的。

//订阅者索引,在 android defaultConfig 中,加入如下:
//在defaultConfig中的代码作用是APT生成的文件名称及路径
    javaCompileOptions {
        annotationProcessorOptions {
            arguments = [eventBusIndex: 'com.testdemo.www.eventbus.MainActivityIndex']
        }
    }
       
    //最后加入
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
    implementation "org.greenrobot:eventbus:3.2.0"

在自定义的 Application 中:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //配置EventBus
        EventBus.builder().addIndex(new MainActivityIndex()).installDefaultEventBus();
    }
}

五、eventBus的使用

1、引入EventBus

implementation "org.greenrobot:eventbus:3.2.0"

2、自定义EventMessage对象

public class EventMessage {
    private int type;
    private String message ;

    public EventMessage(int type, String message) {
        this.type = type;
        this.message = message;
    }
    @Override
    public String toString() {
        return "type="+type+" message= "+message;
    }
}

3、在订阅方法实现的类中,注册和注销EventBus,实现订阅方法

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 注册订阅者
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //注销订阅者
        EventBus.getDefault().unregister(this);
    }
    
    //订阅方法
    @Subscribe(threadMode = ThreadMode.POSTING ,sticky =true)
    public void onMessage(EventMessage) {
        Toast.makeText(this, "收到粘性事件", Toast.LENGTH_SHORT).show();
        Log.e(TAG, "onMessagePosting(), current is " + Thread.currentThread().getName());
        //移除粘性事件
        EventBus.getDefault().removeStickyEvent(event);
    }
}

4、在需要的地方,发送消息

//普通消息
EventBus.getDefault().post(new EventMessage(1,"Hello everyone!"));

//粘性消息
EventBus.getDefault().postSticky(new EventMessage(2,"Hello everyone!"));

六、LiveDataBus的使用

6.1、为什么要用LiveDataBus替代EventBus?

  • LiveDataBus的实现及其简单,相对EventBus复杂的实现,LiveDataBus只需要一个类就可以实现。
  • LiveDataBus可以减小APK包的大小,由于LiveDataBus只依赖Android官方Android Architecture Components组件的LiveData,没有其他依赖,本身实现只有一个类。作为比较,EventBus JAR包大小为57kb,使用LiveDataBus可以大大减小APK包的大小。
  • LiveDataBus依赖方支持更好,LiveDataBus只依赖Android官方Android Architecture Components组件的LiveData,依赖方支持更好。
  • LiveDataBus具有生命周期感知,LiveDataBus具有生命周期感知,在Android系统中使用调用者不需要调用反注册,相比EventBus使用更为方便,并且没有内存泄漏风险。

6.2 、LiveDataBus的组成

  • 消息:消息可以是任何的Object,可以定义不同类型的消息,如Boolean、String。也可以定义自定义类型的消息。
  • 消息通道:LiveData扮演了消息通道的角色,不同的消息通道用不同的名字区分,名字是String类型的,可以通过名字获取到一个LiveData消息通道。
  • 消息总线:消息总线通过单例实现,不同的消息通道存放在一个HashMap中。
  • 订阅:订阅者通过getChannel获取消息通道,然后调用observe订阅这个通道的消息。
  • 发布:发布者通过getChannel获取消息通道,然后调用setValue或者postValue发布消息。

6.3、LiveDataBus的使用

public final class LiveDataBus {

    private final Map<String, BusMutableLiveData<Object>> bus;
    private static volatile LiveDataBus mLiveDataBus;

    private LiveDataBus() {
        bus = new HashMap<>();
    }

    public static LiveDataBus getInstance() {
        if (mLiveDataBus == null) {
            synchronized (LiveDataBus.class) {
                if (mLiveDataBus == null) {
                    mLiveDataBus = new LiveDataBus();
                }
            }
        }
        return mLiveDataBus;
    }

    public interface Observable<T> {

        void post(T value);

        void postDelay(T value, long delay);

        void postDelay(T value, long delay, TimeUnit unit);

        void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer);

        void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer);

        void observeForever(@NonNull Observer<? super T> observer);

        void observeStickyForever(@NonNull Observer<T> observer);

        void removeObserver(@NonNull Observer<? super T> observer);
    }

    private static class BusMutableLiveData<T> extends MutableLiveData<T> implements Observable<T> {

        private class PostValueTask implements Runnable {
            private Object newValue;

            public PostValueTask(@NonNull Object newValue) {
                this.newValue = newValue;
            }

            @Override
            public void run() {
                setValue((T) newValue);
            }
        }

        @NonNull
        private final String key;
        private Map<Observer, Observer> observerMap = new HashMap<>();
        private Handler mainHandler = new Handler(Looper.getMainLooper());

        private BusMutableLiveData(String key) {
            this.key = key;
        }

        private boolean isMainThread() {
            return Looper.getMainLooper().getThread() == Thread.currentThread();
        }

        @Override
        public void post(T value) {
            if(isMainThread()) {
                setValue(value);
            } else {
                mainHandler.post(new PostValueTask(value));
            }
        }

        @Override
        public void postDelay(T value, long delay) {
            mainHandler.postDelayed(new PostValueTask(value), delay);
        }

        @Override
        public void postDelay(T value, long delay, TimeUnit unit) {
            postDelay(value, TimeUnit.MILLISECONDS.convert(delay, unit));
        }

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            SafeCastObserver<T> safeCastObserver = new SafeCastObserver(observer);
            //保存LifecycleOwner的当前状态
            Lifecycle lifecycle = owner.getLifecycle();
            Lifecycle.State currentState = lifecycle.getCurrentState();
            int observerSize = getLifecycleObserverMapSize(lifecycle);
            boolean needChangeState = currentState.isAtLeast(Lifecycle.State.STARTED);
            if (needChangeState) {
                //把LifecycleOwner的状态改为INITIALIZED
                setLifecycleState(lifecycle, Lifecycle.State.INITIALIZED);
                //set observerSize to -1,否则super.observe(owner, observer)的时候会无限循环
                setLifecycleObserverMapSize(lifecycle, -1);
            }
            super.observe(owner, safeCastObserver);
            if (needChangeState) {
                //重置LifecycleOwner的状态
                setLifecycleState(lifecycle, currentState);
                //重置observer size,因为又添加了一个observer,所以数量+1
                setLifecycleObserverMapSize(lifecycle, observerSize + 1);
                //把Observer置为active
                hookObserverActive(safeCastObserver, true);
            }
            //更改Observer的version
            hookObserverVersion(safeCastObserver);
        }

        public void observeSticky(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
            super.observe(owner, new SafeCastObserver<>(observer));
        }

        @Override
        public void observeForever(@NonNull Observer<? super T> observer) {
            if (!observerMap.containsKey(observer)) {
                observerMap.put(observer, new ObserverWrapper(observer));
            }
            super.observeForever(observerMap.get(observer));
        }

        public void observeStickyForever(@NonNull Observer<T> observer) {
            super.observeForever(observer);
        }

        @Override
        public void removeObserver(@NonNull Observer<? super T> observer) {
            Observer realObserver;
            if (observerMap.containsKey(observer)) {
                realObserver = observerMap.remove(observer);
            } else {
                realObserver = observer;
            }
            super.removeObserver(realObserver);
            if (!hasObservers()) {
                LiveDataBus.getInstance().bus.remove(key);
            }
        }

        private int getLifecycleObserverMapSize(Lifecycle lifecycle) {
            if (lifecycle == null) {
                return 0;
            }
            if (!(lifecycle instanceof LifecycleRegistry)) {
                return 0;
            }
            try {
                Field observerMapField = LifecycleRegistry.class.getDeclaredField("mObserverMap");
                observerMapField.setAccessible(true);
                Object mObserverMap = observerMapField.get(lifecycle);
                Class<?> superclass = mObserverMap.getClass().getSuperclass();
                Field mSizeField = superclass.getDeclaredField("mSize");
                mSizeField.setAccessible(true);
                return (int) mSizeField.get(mObserverMap);
            } catch (Exception e) {
                e.printStackTrace();
                return 0;
            }
        }

        private void setLifecycleState(Lifecycle lifecycle, Lifecycle.State state) {
            if (lifecycle == null) {
                return;
            }
            if (!(lifecycle instanceof LifecycleRegistry)) {
                return;
            }
            try {
                Field mState = LifecycleRegistry.class.getDeclaredField("mState");
                mState.setAccessible(true);
                mState.set(lifecycle, state);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private void setLifecycleObserverMapSize(Lifecycle lifecycle, int size) {
            if (lifecycle == null) {
                return;
            }
            if (!(lifecycle instanceof LifecycleRegistry)) {
                return;
            }
            try {
                Field observerMapField = LifecycleRegistry.class.getDeclaredField("mObserverMap");
                observerMapField.setAccessible(true);
                Object mObserverMap = observerMapField.get(lifecycle);
                Class<?> superclass = mObserverMap.getClass().getSuperclass();
                Field mSizeField = superclass.getDeclaredField("mSize");
                mSizeField.setAccessible(true);
                mSizeField.set(mObserverMap, size);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private Object getObserverWrapper(@NonNull Observer<T> observer) throws Exception {
            Field fieldObservers = LiveData.class.getDeclaredField("mObservers");
            fieldObservers.setAccessible(true);
            Object objectObservers = fieldObservers.get(this);
            Class<?> classObservers = objectObservers.getClass();
            Method methodGet = classObservers.getDeclaredMethod("get", Object.class);
            methodGet.setAccessible(true);
            Object objectWrapperEntry = methodGet.invoke(objectObservers, observer);
            Object objectWrapper = null;
            if (objectWrapperEntry instanceof Map.Entry) {
                objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
            }
            return objectWrapper;
        }

        private void hookObserverActive(@NonNull Observer<T> observer, boolean active) {
            try {
                Object objectWrapper = getObserverWrapper(observer);
                if (objectWrapper != null) {
                    Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
                    Field mActive = classObserverWrapper.getDeclaredField("mActive");
                    mActive.setAccessible(true);
                    mActive.set(objectWrapper, active);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private void hookObserverVersion(@NonNull Observer<T> observer) {
            try {
                Object objectWrapper = getObserverWrapper(observer);
                if (objectWrapper != null) {
                    Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass();
                    Field fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion");
                    fieldLastVersion.setAccessible(true);
                    //get livedata's version
                    Field fieldVersion = LiveData.class.getDeclaredField("mVersion");
                    fieldVersion.setAccessible(true);
                    Object objectVersion = fieldVersion.get(this);
                    //set wrapper's version
                    fieldLastVersion.set(objectWrapper, objectVersion);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static class ObserverWrapper<T> implements Observer<T> {

        @NonNull
        private final Observer<T> observer;

        ObserverWrapper(@NonNull Observer<T> observer) {
            this.observer = observer;
        }

        @Override
        public void onChanged(@Nullable T t) {
            if (isCallOnObserve()) {
                return;
            }
            try {
                observer.onChanged(t);
            } catch (ClassCastException e) {
                e.printStackTrace();
            }
        }

        private boolean isCallOnObserve() {
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            if (stackTrace != null && stackTrace.length > 0) {
                for (StackTraceElement element : stackTrace) {
                    if ("androidx.lifecycle.LiveData".equals(element.getClassName()) &&
                            "observeForever".equals(element.getMethodName())) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

    private static class SafeCastObserver<T> implements Observer<T> {

        @NonNull
        private final Observer<T> observer;

        SafeCastObserver(@NonNull Observer<T> observer) {
            this.observer = observer;
        }

        @Override
        public void onChanged(@Nullable T t) {
            try {
                observer.onChanged(t);
            } catch (ClassCastException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized <T> Observable<T> with(String key, Class<T> type) {
        if (!bus.containsKey(key)) {
            bus.put(key, new BusMutableLiveData<>(key));
        }
        return (Observable<T>) bus.get(key);
    }
}

注册订阅:

         LiveDataBus.getInstance().with("string", String.class)
                 .observe(this, new Observer<String>() {
                     @Override
                     public void onChanged(String s) {
                         Log.d(TAG, "onChanged: " + s);
                     }
                 });

发送消息:

LiveDataBus.getInstance().with("string", String.class).post("string");

本篇文章结合其他博主分享整合而成,又加入自己的理解,如有错误,欢迎大家留言!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值