4

我的应用程序具有用户交互活动和后台服务,这是修改数据模型的唯一地方。后台服务侦听用户所做的操作以及来自网络的传入消息。因此可能会出现并发问题,我试图通过使用处理程序来防止这些问题。对于事件层,我使用 greenrobots Eventbus。

这一切都很好,但我想知道是否有更智能/更快/更少代码扩展(因此更不容易出错)的方式来处理这个用例?

更加具体:

  • 有没有办法确保在没有处理程序的情况下串行执行 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;
}

对于每个感兴趣的事件,我确实有一个 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;
    }   
}
4

1 回答 1

3

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

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

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

如果您知道确实需要支持此类上的其他公共方法,那么执行您在此处所做的操作至少可以将所有 onEvent() 方法处理到单个线程上(用于创建 Looper 的线程的 Looper我在 Looper 类的文档中读到的内容)并且至少简化了一些事情。然后,您可能还需要对公共方法和所有其他方法(例如 processEditUserBroadcast()这节课。或者,根据这些数据成员是什么以及您的需求,您可以通过简单地使其中一些成为易失性、原子性或使用并发集合等来解决问题。

这有帮助吗?对于那些精通 Android、Loopers、Handlers、GreenRobot EventBus 等的人,我说错了吗?

于 2015-01-21T05:03:22.660 回答