1

私は最新の Android プロジェクトで試してみましたOttoが、オブジェクト間の通信が大幅に簡素化されました。ただし、スレッド間の通信に隠れた問題があるかどうかはわかりません。

バスがどこからでもアクセスできるように、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スレッド間の通信に Otto を使用することで隠れたエラーが発生する可能性はありますか? このアプローチに問題はありますか?

4

2 に答える 2

5

Otto は、イベントがポストされたのと同じスレッドで同期的にイベントをディスパッチします。予想されるスレッドからメソッドを呼び出すことを確認するためだけに存在します。メインスレッドのみからあなたをアサートします。バックグラウンド スレッドからを使用すると、バスは実行時例外をスローし、間違ったことをしないように警告します。基本的にノーチェックで行います。どのスレッドからでも呼び出すことができますが、既に述べたように、サブスクライバーはどのスレッドからも呼び出されることを期待する必要があります。ThreadEnforcerpost()ThreadEnforcer.MAINpost()ThreadEnforcer.MAINpost()ThreadEnforcer.ANYpost()

コードに適用するKeyPairCreatedEventと、バックグラウンドから投稿され、keyPairCreated(KeyPairCreatedEvent)サブスクライバーもそのバックグラウンド スレッドで呼び出されます。2 つのスレッド (バックグラウンドとメイン) が同じデータで動作する場合は、同期する必要があります。そうしないと、矛盾が生じる可能性があります。(同期を避けるために)結果をメインスレッドで配信したい場合は、そこから使用Handler.post()して呼び出す必要bus.post()があります。

または、 Otto と同じインターフェイスを使用するTinyBusを試すこともできますが、イベントがバックグラウンド スレッドからポストされた場合でもメイン スレッドでサブスクライバーを呼び出します。

お役に立てれば。

于 2014-11-21T21:36:22.703 に答える
1

Otto のディスパッチ キューは ThreadLocal でラップされているため、サブスクライバー メソッドで受信したイベントを処理する際に並行性を考慮していれば問題ありません。

于 2014-11-18T06:07:28.573 に答える