使用Otto在线程之间进行通信:会引起任何问题吗? [英] Using Otto for communication between threads: Can it cause any problems?

查看:108
本文介绍了使用Otto在线程之间进行通信:会引起任何问题吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在最新的Android项目中试用了Otto,它确实确实简化了许多对象之间的通信.但是,我不确定在Threads之间进行通信是否会存在任何隐藏的问题.

I've tried out Otto in my latest Android project, and it really does simplify communication between Objects a ton. However, I'm not certain if there can be any hidden problems from communicating between Threads with it.

这就是我所做的,使用enum创建了SingletonBus,以便可以在任何位置访问总线:

This is what I did, created a SingletonBus using an enum so that the Bus is accessible anywhere:

public enum SingletonBus {
    INSTANCE;

    private static String TAG = SingletonBus.class.getSimpleName();

    private Bus bus;

    private boolean paused;

    private final Vector<Object> eventQueueBuffer = new Vector<>();

    private Handler handler = new Handler(Looper.getMainLooper());

    private SingletonBus() {
        this.bus = new Bus(ThreadEnforcer.ANY);
    }

    public <T> void postToSameThread(final T event) {
        bus.post(event);
    }

    public <T> void postToMainThread(final T event) {
        try {
            if(paused) {
                eventQueueBuffer.add(event);
            } else {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            bus.post(event);
                        } catch(Exception e) {
                            Log.e(TAG, "POST TO MAIN THREAD: BUS LEVEL");
                            throw e;
                        }
                    }
                });
            }
        } catch(Exception e) {
            Log.e(TAG, "POST TO MAIN THREAD: HANDLER LEVEL");
            throw e;
        }
    }

    public <T> void register(T subscriber) {
        bus.register(subscriber);
    }

    public <T> void unregister(T subscriber) {
        bus.unregister(subscriber);
    }

    public boolean isPaused() {
        return paused;
    }

    public void setPaused(boolean paused) {
        this.paused = paused;
        if(!paused) {
            Iterator<Object> eventIterator = eventQueueBuffer.iterator();
            while(eventIterator.hasNext()) {
                Object event = eventIterator.next();
                postToMainThread(event);
                eventIterator.remove();
            }
        }
    }
}

然后,我创建了一个Event,它可以包含操作的结果(我还没有为任何子类创建子类,而是为每个操作创建一个Event,但是当它变得混乱时,我将尝试对其进行重构.必不可少):

Then I created an Event which can contain the result of an operation (I'm not subclassing anything yet but creating an Event for each operation, but I'll try refactoring it when it'll get messy if it'll be necessary):

public class KeyPairCreatedEvent {
    private KeyPair keyPair;

    public KeyPairCreatedEvent(KeyPair keyPair) {
        this.keyPair = keyPair;
    }

    public KeyPair getKeyPair() {
        return keyPair;
    }
}

然后我创建并发布了此事件:

And then I created and posted this event:

@Subscribe
public void keyPairCreate(KeyPairCreateEvent keyPairCreateEvent) {
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                KeyPair keyPair = keyPairCreator.createKeyPair();
                SingletonBus.INSTANCE.getBus().post(new KeyPairCreatedEvent(keyPair));
            } catch(...){...}
        }
    });
    thread.start();
}

并订阅了一个事件以在创建密钥对时获取结果:

And subscribed an event to get the result when the keypair was created:

@Subscribe
public void keyPairCreated(KeyPairCreatedEvent keyPairCreatedEvent) {
    Log.d(MainActivity.class.getName(), "Acquired keypair: " + keyPairCreatedEvent.getKeyPair());
    //do stuff
}

我的问题是,它似乎正在运行,但是使用Otto和ThreadEnforcer.ANY在线程之间进行通信是否会存在任何隐藏的错误?这种方法有什么问题吗?

My question is, it seems to be working, but can there be any hidden errors from using Otto with ThreadEnforcer.ANY to communicate between threads? Is there anything wrong with this approach?

推荐答案

Otto在相同线程同步调度事件,并在其中发布事件. ThreadEnforcer仅用于验证您是否从预期线程中调用了post()方法. ThreadEnforcer.MAIN断言您post()仅来自主线程.如果从后台线程使用ThreadEnforcer.MAINpost(),则bus将抛出运行时异常,警告您不要做错事.使用ThreadEnforcer.ANY时,基本上不会进行任何检查.您可以从任何线程进入post(),但是,正如我已经说过的,您还必须期望从任何线程也可以调用订户.

Otto dispatches events synchronously in the same thread, in which they were posted. ThreadEnforcer is there just to verify, that you call post() method from the expected thread. ThreadEnforcer.MAIN asserts that you post() from main thread only. If you use ThreadEnforcer.MAIN and post() from a background thread, then bus will throw a runtime exception warning you from doing wrong things. With ThreadEnforcer.ANY no checks are basically done. You are allowed to post() from any thread, but, as I already said, you have to expect subscribers to be called from any thread too.

应用于您的代码,这意味着KeyPairCreatedEvent将从后台发布,并且keyPairCreated(KeyPairCreatedEvent)订阅者也将在该后台线程中被调用.如果两个线程(后台线程和主线程)在同一数据上工作,则必须进行同步,否则可能导致不一致.如果要在主线程中传递结果(以避免同步),则需要使用Handler.post()并从那里调用bus.post().

Applied to your code it means KeyPairCreatedEvent will be posted from a background and keyPairCreated(KeyPairCreatedEvent) subscriber will also be called in that background thread. If two threads (background and main) work on same data, then you have to synchronize, otherwise it could lead to inconsistencies. If you want to have your result delivered in main thread (to avoid synchronization), then you need to use Handler.post() and call bus.post() from there.

或者,您可以尝试 TinyBus ,该接口使用与Otto相同的接口,但在main中调用订户即使事件是从后台线程发布的,也是如此.

Alternatively, you can try out TinyBus, which uses same interfaces as Otto, but calls subscribers in main thread even when events were posted from a background thread.

希望这会有所帮助.

这篇关于使用Otto在线程之间进行通信:会引起任何问题吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆