BroadcastReceiver
approach when are used to communicate from a long running thread to UI layer (eg. notify the activity that a download was finished and send some response data from a Worker Thread
so that the activity can display the appropriate message to the user) just inside of a single application? (Note that I am not using Android Service
for background work.. just AsyncTask
and Thread
s)This is a very interesting question and I ran into the same problem. In my opinion both mechanisms can be used altogether and the right approach to use depends on your use case. Here are some points to be taken into account before deciding.
Using the callback-mechanism has some benefits, but there are also limitations:
PRO
PRO
PRO
- It is simple and straight forward to implement.
- You get type-safety between the components that interact with each other.
- You can return arbitrary objects.
- It simplifies testing as you only have to inject a mock-callback (e.g. generated through mockito or something similar) in unit tests.
- You have to switch to the main thread in order to do UI manipulations.
- You can only have a 1-to-1 relationship. A 1-to-n relationship
(observer pattern) is not realizable without further work. In this case I
would prefer Android's
Observer
/Observable
mechanism. - As you already said, you always have to check for
null
before invoking callback functions if the callback may be optional. - If your component should offer a kind of service API with different service functions and you do not want to have a callback interface with only a few generic callback functions, you have to decide whether you provide a special callback interface for each service function or whether you provide a single callback interface with a lot of callback functions. In the later case all callback clients used for service calls to your API have to implement the complete callback interface although the majority of the method bodies will be empty. You can work around this by implementing a stub with empty bodies and make your callback client inherit from that stub, but this is not possible if already inheriting from another base class. Maybe you can use some kind of dynamic proxy callback (see http://developer.android.com/reference/java/lang/reflect/Proxy.html), but then it gets really complex and I would think of using another mechanism.
- The client for the callback calls has to be propagated through various methods/components if it is not directly accessible by the caller of the service.
BroadcastReceiver
-approach:PRO
- You achieve a loose coupling between your components.
- You can have a 1-to-n relationship (including 1-to-0).
- The
onReceive()
method is always executed on the main thread. - You can notify components in your entire application, so the communicating components do not have to "see" eachother.
- This is a very generic approach, so marshalling and unmarchalling of data transported by the
Intent
is an additional error source. - You have to make your
Intent
's actions unique (e.g. by prepending the package name) if you want to eliminate correlations with other apps, as their original purpose is to do broadcasts between applications. - You have to manage the BroadcastReceiver-registration and
unregistration. If you want to do this in a more comfortable way, you
can implement a custom annotation to annotate your Activity with the
actions that should be registered and implement a base
Activity
class that does registration and unregistration withIntentFilter
s in itsonResume()
resp.onPause()
methods. - As you already said, the data that is sent with the
Intent
has to implement theParcelable
interface, but furthermore there is a strict size limitation and it will cause performance issues if you transport a large amount of data with yourIntent
. See http://code.google.com/p/android/issues/detail?id=5878 for a discussion on that. So if you want to send images for example you have to store them temporary in a repository and send a corresponding ID or URL to access the image from the receiver of yourIntent
that deletes it from the repository after usage. This leads to further problems if there are several receivers (when should the image be removed from the repository and who should do that?). - If you overuse this kind of notification mechanism the control flow
of your application may get hidden and when debugging you end up drawing
graphs with sequences of
Intent
s to understand what has triggered a specific error or why this notification chain is broken at some point.
AsyncTask
or HandlerThread
if using MessageQueue
s)
inside the core layer and the UI should be updated once this task has
been finished. In general with callbacks you achieve a tight coupling
between your components, so I would prefer using this approach only
within a layer and not for communication across layer boundaries. For
message broadcasting between UI- and core-layer I would use the BroadcastReceiver
-approach that lets you decouple your UI layer from the logic layer.
Không có nhận xét nào:
Đăng nhận xét