-->

使用奥托线程间通信:它可能会导致什么问题?(Using Otto for communication

2019-10-21 06:54发布

我已经试过了Otto在我最新的Android项目,它确实简化了对象之间的通信吨。 但是,我不能肯定是否有可能从它的线程之间通信的任何隐患。

这是我做的,创造了一个SingletonBus使用enum ,这样的公交车是任何地方访问:

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可以包含一个操作的结果(我没有继承任何东西,但在创建每个操作的事件,但我会尝试重构它的时候,它会变得混乱,如果它会是必要的):

public class KeyPairCreatedEvent {
    private KeyPair keyPair;

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

    public KeyPair getKeyPair() {
        return keyPair;
    }
}

然后我创建并张贴了这个事件:

@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();
}

而订阅一个事件,得到的结果是创建密钥对时:

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

我的问题是,它似乎是工作,但也有从使用奥托与任何隐藏的错误ThreadEnforcer.ANY线程之间的沟通? 有什么不对这种方法?

Answer 1:

奥托同步调度事件在同一个线程 ,它们被公布。 ThreadEnforcer在那里只是为了验证,您致电post()与预期线程方法。 ThreadEnforcer.MAIN断言你post()只从主线程。 如果您使用ThreadEnforcer.MAINpost()从后台线程,则总线将做错了事情引发运行时异常警告你。 随着ThreadEnforcer.ANY没有检查基本完成。 你被允许post()从任何线程,但是,正如我已经说过,你要指望用户能够从任何线程调用了。

应用到你的代码,这意味着KeyPairCreatedEvent会从后台发布和keyPairCreated(KeyPairCreatedEvent)用户也将在后台线程调用。 如果两个线程(背景和主要)在同一个数据的工作,那么你必须同步,否则就可能导致不一致。 如果您希望您的结果主线程交付(以避免同步),那么你需要使用Handler.post()并调用bus.post()从那里。

或者,你可以尝试TinyBus ,它使用相同的接口,奥托,而是调用主线程的用户,即使事件从后台线程发布。

希望这可以帮助。



Answer 2:

在奥托调度队列是包裹着ThreadLocal的,所以如果你已经在你的用户收到的方法处理事件时,会考虑并发性就没有问题。



文章来源: Using Otto for communication between threads: Can it cause any problems?