Лучшая практика для 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);
}
Всякий раз, когда я реагирую на входящее событие, я хочу обеспечить последовательное выполнение, поскольку могут быть проблемы с параллелизмом, потому что есть входящие события от взаимодействий пользователя, а также от других пользователей через сеть. Поэтому я решил поработать с обработчиком:
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);
}
Методы "process.." - это то место, где происходит "волшебство данных", и оно не должно относиться к моему вопросу.
И, конечно, для каждого возможного события я создавал класс, который обычно довольно тонкий, как этот:
public class JoinParty {
private String partyCode;
public JoinParty(String partyCode) {
super();
this.partyCode = partyCode;
}
public String getPartyCode() {
return partyCode;
}
}
1 ответ
Спасибо за размещение этого Матиаса! Я думаю, что вы подняли очень важный вопрос о безопасности потоков с 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 и т. Д., Я вообще что-то не так написал?