4

私のアプリには、ユーザー インタラクションのアクティビティと、データ モデルが変更される唯一の場所であるバックグラウンド サービスがあります。バックグラウンド サービスは、ネットワークからの着信メッセージだけでなく、ユーザーが行ったアクションもリッスンします。したがって、並行性の問題が発生する可能性がありますが、ハンドラーを使用して防止しようとしています。イベント レイヤーには、greenrobots Eventbus を使用します。

これはすべてうまく機能していますが、このユースケースを処理するための、よりスマートで高速なコードの広範ではない (したがって、エラーが発生しにくい) 方法があるのだろうか?

もう少し詳しく言うと:

  • ハンドラーなしで onEvent メソッドのシリアル実行を保証する方法はありますか?
  • 考えられるイベントごとに onEvent メソッドを持つことに代わるものはありますか?
  • 私がここでやっていることのより良いパターンはありますか?

これが私のアプローチです:

oncreate メソッドでサービスを登録します(アクティビティの場合は onstart でこれを行います)

@Override
public void onCreate() {
    super.onCreate();
    ...
    EventBus.getDefault().register(this);
}

そして onDestroy で、もう一度登録を解除します。

@Override
public void onDestroy() {
    super.onDestroy();
    ....
    EventBus.getDefault().unregister(this);
}

着信イベントに反応するときはいつでも、同時実行の問題が発生する可能性があるため、シリアル実行を保証したいと考えています。これは、ユーザー インタラクションやネットワーク経由の他のユーザーからの着信イベントがあるためです。そこで、ハンドラーを使用することにしました。

private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            Object receivedEvent = msg.obj;
            if(receivedEvent instanceof EditUser)
            {
                processEditUserBroadcast((EditUser)receivedEvent);
            }           
            else if(receivedEvent instanceof JoinParty)
            {
                processJoinPartyBroadcast((JoinParty)receivedEvent);
            }
            else if(receivedEvent instanceof LeaveParty)
            {
                processLeavePartyBroadcast();
            }
            else if(receivedEvent instanceof SendMessage)
            {
                processSendMessageBroadcast((SendMessage)receivedEvent);
            }
            else if(receivedEvent instanceof ReceivedMessage)
            {
                processReceivedMessageBroadcast((ReceivedMessage)receivedEvent);
            }       
            else if(receivedEvent instanceof Reset)
            {
                processResetBroadcast();
            }
            else if(receivedEvent instanceof ImageDownloadFinished)
            {
                processImageDownloadFinishedBroadcast((ImageDownloadFinished)receivedEvent);
            }
        }
    };  
    return handler;
}

関心のあるイベントごとに、小さな「passToHandler」ヘルパー関数を介してシリアル実行を保証するために、イベントをハンドラーに渡すだけの onEvent メソッドがあります。

public void passToHandler(Handler handler, Object object)
{
    Message message = handler.obtainMessage();
    message.obj = object;
    handler.sendMessage(message);
}

public void onEvent(EditUser editUser)
{
    passToHandler(handler,editUser);
}

public void onEvent(JoinParty joinParty)
{
    passToHandler(handler,joinParty);
}

public void onEvent(LeaveParty leaveParty)
{
    passToHandler(handler,leaveParty);
}

public void onEvent(SendMessage sendMessage)
{
    passToHandler(handler,sendMessage);
}

public void onEvent(ReceivedMessage receivedMessage)
{
    passToHandler(handler,receivedMessage);
}

public void onEvent(Reset reset)
{
    passToHandler(handler,reset);
}

public void onEvent(ImageDownloadFinished imageDownloadFinished)
{
    passToHandler(handler,imageDownloadFinished);
}

「プロセス..」メソッドは「データマジック」が発生する場所であり、私の質問には関係ありません。

そしてもちろん、可能なイベントごとに、通常は次のように非常にスリムなクラスを作成しました。

public class JoinParty {
    private String partyCode;

    public JoinParty(String partyCode) {
        super();
        this.partyCode = partyCode;
    }
    public String getPartyCode() {
        return partyCode;
    }   
}
4

1 に答える 1

3

このマティアスを投稿してくれてありがとう!GreenRobot EventBus のスレッド セーフについて、ユーザーが見落としがちな非常に重要な点を指摘されたと思います。

私は GreenRobot EventBus と Android (ただし Java は除く) は初めてですが、おそらく正しい道を進んでいると思います。GreenRobot EventBus ソース コードを正しく読んだ場合、このアプローチのもう 1 つの利点は、SendMessage イベントの onEvent() メソッドへのポストが (Handler で sendMessage を呼び出した後) すぐに返され、EventBus が他のイベントへのポストを続行できることです。クラスによる実際の処理の遅延なしにサブスクライバー。ただし、これはあなたが望むものかもしれませんし、そうでないかもしれません。

あなたが与えたアプローチでは、あなたがこのようなアプローチをとる場合、 onEvent() メソッドと processEditUserBroadcast( )。そうしないと、EventBus から受信したイベントのすべての処理が実際には 1 つのスレッドで (シリアルに) 処理されることを確認したにもかかわらず、他のクラスが別のスレッドでこのクラスのパブリック メソッドを呼び出して、安全性の問題をもう一度スレッド化します。

このクラスで他の public メソッドをサポートする必要があることがわかっている場合、ここで行ったことを実行すると、少なくとも onEvent() メソッドのすべてが 1 つのスレッド (Looper を作成するスレッドの Looper のスレッド) で処理されます。私がルーパークラスのドキュメントで読んだこと)、それは少なくともいくつかのことを簡素化します. 他のパブリック メソッドをオンにする場合、複数のスレッドからクラスのデータ メンバーへの安全なアクセスを保証するために、パブリック メソッドと processEditUserBroadcast() などの他のすべてのメソッドに何らかの同期を適用する必要がある場合もあります。このクラス。または、それらのデータ メンバーが何であるか、およびニーズが何であるかに応じて、それらの一部を揮発性、アトミックにする、または同時コレクションなどを使用するだけでうまくいく場合があります。

これはまったく役に立ちますか?Android、ルーパー、ハンドラー、GreenRobot EventBus などに精通している人にとって、私はまったく間違って話しているのでしょうか?

于 2015-01-21T05:03:22.660 に答える