具有线程安全性的eventbus的最佳实践

时间:2015-01-06 07:07:44

标签: android design-patterns thread-safety handler greenrobot-eventbus

我的应用程序包含用户交互活动和后台服务,后台服务是修改数据模型的唯一位置。后台服务侦听用户所做的操作以及来自网络的传入消息。因此,我试图通过使用处理程序来防止并发问题。 对于事件层,我使用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);
}

每当我对传入的事件做出反应时,我都希望确保串行执行,因为可能存在concurreny问题,因为来自用户交互的传入事件以及来自其他用户的传入事件都是通过网络传播的。所以我决定使用一个处理程序:

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;
}

对于每个感兴趣的事件,我都有一个onEvent方法,除了将事件传递给处理程序之外什么也不做,以确保通过一个小的“passToHandler”辅助函数执行串行执行

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;
    }   
}

1 个答案:

答案 0 :(得分:3)

感谢您发布此Matthias!我认为你提出了一个关于GreenRobot EventBus的线程安全的一个非常重要的观点,用户很容易错过它。

我认为你很可能正走在正确的道路上,虽然我是GreenRobot EventBus和Android(但不是Java)的新手。如果我正确读取了GreenRobot EventBus源代码,这种方法的另一个可能的好处是,发送到onEvent()方法的SendMessage事件会立即返回(在Handler上调用sendMessage之后),允许EventBus继续将其发布到任何其他订阅者没有延迟您班级的实际处理。这可能是也可能不是你想要的。

使用您提供的方法,您需要确保的另一件事是,如果您采用这样的方法,那么您的类中没有其他公共方法具有所有onEvent()方法和方法as processEditUserBroadcast()。否则,虽然您已确保从EventBus接收的事件的所有处理实际上是在单个线程上(以串行方式)处理,但是其他一些类可能在另一个线程上调用此类的公共方法,然后导致你再次解决安全问题。

如果你知道你确实需要在这个类上支持其他公共方法,那么你在这里做的事情至少会把所有的onEvent()方法处理到一个线程上(对于创建的线程来说,是Looper的)我在Looper课程的文档中读到的Looper,至少可以简化一些事情。您可能还需要对公共方法和所有其他方法(如processEditUserBroadcast())应用一些同步,以便保证从多个线程安全访问类的数据成员,如果您要使用其他公共方法这个班。或者,取决于那些数据成员是什么以及您的需求是什么,您可能只需简单地使其中的一些成为易失性,原子或使用并发集合等等。这一切都取决于读写访问权限需求以及这些访问所需的粒度。

这有帮助吗?对于那些精通Android,Loopers,Handlers,GreenRobot EventBus等的人,我有什么想法吗?