Why should I not use a message bus instead of a Loaders and Services?
Asked Answered
U

3

20

In typical Android project where we need to pull data from somewhere (REST, SQL, cache, etc) into the UI in a clean way we commonly use a Loader, Service or (possibly, yuk) an AsyncTask, but I find all these approaches unsatisfactory for several reasons:

  • They're ugly, especially Loaders which have an appalling API structure
  • It's too easy to get wrapped up in threads, and tread on the UI thread
  • Our presentation layer code is being polluted with Android code and boilerplate. We're often passing Android objects (eg Cursors) right up into to the UI layer, which makes a clean architecture almost impossible to achieve. This forces us to mix business domain specific code (ideally plain Java objects) with Android platform code - not great for readability, maintenance, testing, or flexibility for future development. In practice we often get huge, messy Activity/Fragment classes.

I'm attracted by ideas such as those outlined in these articles: http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/ http://antonioleiva.com/mvp-android/ http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

Having successfully started using MVP to break the Activities/Fragments/Views into smaller/cleaner pieces, I'm now thinking that a solution to the problems above might be to rely on a message bus (Otto, EventBus, etc) instead of services or loaders or whatever to interact with the domain data.

So in practice that would mean instead of using (for example) a CursorLoader to load a Cursor from the database, I'd instead use the message bus to send a message to request data, the data is loaded on a background thread in response to that message, and then handle the response data when it arrives via a message on the UI thread. Crucially for me I'd prefer that data structure to be cast out of the business domain, not the Android domain, so I'd prefer an array of business objects, to a Cursor.

This being engineering there are always trade-offs, and although this seems to provide a much cleaner separation of concerns, there's less loader/service boilerplate, what are the downsides?

  • It may be harder (especially for new developers) to understand the code
  • It will be necessary to ensure the messages are sent and received on the right threads (Otto seems like it may have limitations here)
  • It will be necessary to avoid the temptation to implement everything as a message, which would ultimately be counterproductive
  • Passing collections of business objects around may be less efficient than using objects like Cursors. Though in many scenarios is it a problem in practice?
  • I do not know if Otto/EventBus are designed only to pass very small messages, or whether it is appropriate to pass larger objects (eg an array of business objects).

My question is are there any fundamental reasons NOT to take this message-based approach with Android apps?

Ubiety answered 20/2, 2015 at 12:55 Comment(0)
Y
2

any fundamental reasons NOT to take this message-based approach with Android apps

There is no, I guess. In my practice I worked with 'stock' stuff like Loaders and AsyncTasks (I would not put Services in this row, because its responsibility is much broader). Then bus thing was implemented, and guess what? Life became easier and more predictable, decoupling increased. Once I totally moved to Rx, work became not only easier, but funnier! However, nothing will save you from dealing with lifecycles.

All this is just implementation details, it's more important to keep global things clear. When you talk about Clean Architecture, the thing is to hide from the UI layer (Activities, Fragments, Views..) how and where the objects come. Once you incapsulate this certain job in usecases, it's not a big deal which tool to use: loaders, buses or Rx - your UI layer should only stick to the interface provided by usecase - callbacks, events or observables

I'd point two things:

  1. The less any layer knows about the usecase implementation the better.
  2. If you've chosen one particular tool for implementation, use it everywhere. Do not mix several tools for the same job.
Yockey answered 10/10, 2015 at 19:33 Comment(0)
U
1

They have provided explanations for their own resistance to such approaches:

1. Be careful with code abstractions.

2. Avoid dependency injection frameworks.

3. Avoid Creating Unnecessary Objects.

4. Avoid Internal Getters/Setters.

Unrounded answered 20/2, 2015 at 13:23 Comment(1)
The first article says "So if your abstractions aren't supplying a significant benefit, you should avoid them" so more of a warning to be careful than a rule against it. The second (DI) seems a bit out of date as the likes of Dagger are much more efficient. The last one definitely seems like a downside of this approach, but unless the dataset is large or the code called regularly (eg an adapter) is it enough to wipe out the benefits of cleaner code? I'm not so sure...Ubiety
O
0

A few years ago there were not strong android devices which has 3 gb ram or more. When you have a network call from your app and your app gets interrupt such as you get a phone call and send your app to background (if you do not use a service) your app get killed and you waste your network call. If you have a running service binded your application, your app will get a low priority to get killed by Android OS

Also with services you can make your non-ui works or long live processes separeted from ui-thread. It's a good approach for non-blocking-ui app. Also you can handle the orientation changes.

Nowadays as you say there are some other options (libraries, patterns etc) in Android Dev. world such as MVP, MVC, MVVM, Retrofit, OttoBus...

I think there's not a certain correct way for developing your Android app such as "you have to use MVP, Retrofit, services, loaders, MVVM, Data Binding etc.."

But while you're developing an Android app you can consider these principles and you can make your pattern and library choices according to these principles. (The order of principles can be changed according to your project, time, resources etc..)

1- Clean code
2- Seperate layers
3- Non Blocking Ui
4- Don't waste user's resources. (Avoid unneccassry network calls, memory allocation etc.)
5- Support orientation change.
6- Testing 
7- Clean Ui Design (Material Design)

This's an old video but every Android Developer should watch it: https://www.youtube.com/watch?v=xHXn3Kg2IQE

Owenism answered 29/6, 2016 at 11:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.