I have a started service that handles a connection and that keep an array of objects. On the other hand, I have a singleton that should bind to that service in order to get one of the objects handled by the service. So, how could I bind the service from the singleton? Is it a good practice to bind the service when the singleton is initialized by using the application's context? Is there a better alternative?
Thanks in advance!
This is a perfectly good way to do it. Your singleton gets initialized and binds to the service using application context. The singleton will stay bound until the process hosting your singleton is killed by Android (or until you intentionally unbind). Be aware that if you intentionally unbind then you will need to intentionally bind again if your app starts again before Android has destroyed the hosting process (or you'll need to destroy your singleton so it gets reinitialized later).
In the case where Android kills your process and the user returns to the app, your singleton will get recreated and will rebind to the service.
Related
I have a service, I need to communicate to with it (one service - many fragments/activities). There are two options for this:
Have a singleton that controls the service - starts it and then binds to it (using the app context)
Have a singleton that controls the service - starts it, the service when ready registers back as a delegate to the singleton (in a WeakReference)
Solution no 2 seems simpler to me, but whenever I read about communication with services there is the concept of the bound service.
Is there any benefit of having a bound service instead of the service registering itself as a delegate (and unregistering with onDestroy)?
Edit 1: The service is to keep the communication alive, it's expensive to set up a new communication channel. Even if no one requested any data it should keep the channel alive (heartbeat).
The service is foreground, it should run even if the activity that requested the data gets killed by the system. The next time it is created the data will be there.
The data requested by one screen might be useful for some other (therefore has to be stored in a singleton).
Bound and unbound services are both usable patterns and you should pick whatever pattern is better for you use case.
You should pick bound service if you want your service to have the same lifecycle as the components that bind to it. If you need an independent service use an unbound version.
The only benefit of one approach versus another is the simplicity of implementation.
In you case, I think you need the service only while there are running activities and fragments, then the easiest way, in my opinion, would be to make a bound service and make every activity bind to it. With that, you'll get a simple communication interface between you activities (and fragments, since they have access to containing activity) and your service.
The benefits of this approach are:
the service will stop itself if all activities unbind and start itself when first activity binds to it.
you won't need to track all running activities in the singleton and manually unbind
you won't need to maintain a singleton manager, less code -> less bugs
sometimes onDestroy can be skipped by the system and you can leak the service with the 2 approach.
Since you need your service to be running the correct option will be to use a started service and make each activity bind to it when needed. It's a common pattern.
Started service will run until you explicitly stop it or it stops itself, you can have a singleton manager that will be responsible for that.
But at the same time you can communicate with the service from your activity using binding.
So basically comparing with the first suggested approach, you'll need some instance that will start and stop the service, but the communication between activities and service will be the same - using binding.
Yes, using a bound service in Android is a much better option when communicating with Views like Activities/Fragments. This is because of the following reasons,
It runs synchronously.
You can have more control on the service data when to show on UI thread of the view. You can choose when to call it in async/sync way.
LocalBroadcastManager only runs Asynchronously.
I am trying to use a static singleton DataManager that makes network requests and holds arrays of data for my Activity, instantiated in my Activity's onCreate() class, but the idea that the Activity gets destroyed every time there is an orientation change is tripping me up. I don't want to re-create a new singleton and re-populate it with data every time the user changes the orientation or comes back to the screen.
Even if I make DataManager a Service, if I make it a Bound Service, it seems like the Service will get destroyed whenever my Activity gets destroyed, but if I don't make it a bound service and use startService() and stopService() in my Activity, it also gets destroyed whenever my Activity is destroyed.
Also, if I use onSaveInstanceState() and onRestoreInstanceState() to save my instance of the singleton, it possible that my singleton would get destroyed when my Activity is inactive, since there is no longer a pointer to it. Then Activity B using the same DataManager class could create another DataManager instance while Activity A is inactive. Then Activity A wakes up, inflating another Data Manager, giving us 2 DataManagers that are no longer singletons and may have inconsistent data.
I have read elsewhere that I should not subclass Application to maintain app state, but I don't understand how it would work any other way. Thanks for any clarification.
Subclass the application class and then instantiation your singleton within the application.onCreate() callback. This way it will be available for the lifetime of your application rather than the lifetime of a single activity. Careful that this won't be garbage collected until someone kills your app so don't have too many "Global" singletons.
DO NOT do the work in Application.onCreate(). You will be slowing down your application start up, no matter what happens. This is not advised for Android applications, you want your app to start promptly.
Instead, if you really need a singleton, have it construct lazily when it's necessary.(If you are sure you will use it, you you can also force the construction asynchronously from a separate thread when your activity starts). When your activity gets destroyed, it doesn't mean the whole process will be immediately torn down, so your singleton will stay alive.
Also, if you are using a singleton, make sure to be able to clear it when memory is low. You will need to implement Application.onTrimMemory(int) and clear the singleton from there.
From what I can tell, a Service can only be accessed from an Activity via an IBinder, Messenger or AIDL.
Why can a service instance's methods not be directly called by, for example, an activity?
For example, when the service is started, have the service save its instance in a singleton which would then be accessed by Activitys, allowing them to directly call the service's methods?
From what I can tell, a Service can only be accessed from an Activity via an IBinder, Messenger or AIDL.
That would depend upon what you define as "accessed". startService() can also be used to direct the service to perform some operation.
Why can a service instance's methods not be directly called by, for example, an activity?
Android's component model is designed around loose coupling and replaceable implementations, where the replacements may be local or remote.
Moreover, a service should only be running when it is actively delivering value to the user. As such, there will be plenty of times when the service is not yet running, and the activity would need to start or bind to the service anyway.
For example, an IntentService should only be interacted with via startService(), as the IntentService will only be running while there are commands (supplied via startService()) to be processed.
Finally, the primary role of a Service is as a marker to the OS, letting it know that the process is still doing work, even while it is in the background. A pattern of "let's stuff the Service into a singleton" suggests that you are using the service in cases where the object in question does not necessarily need to be a Service. Just because an object is a singleton does not mean that it needs to be a Service. Hence, you need to sit back and ensure you know exactly why you are using a Service in the first place and whether that is best for the user.
For example, when the service is started, have the service save its instance in a singleton which would then be accessed by Activitys, allowing them to directly call the service's methods?
There's nothing stopping you from doing this. I wouldn't -- I'll use startService() and event buses for communications. And, while it is technically possible to do what you want, whether it is sensible and reliable depends entirely upon the use case of the service and the communications with that service.
Is there a potential issue using a Singleton Java class by both a Service and Activity in an Android application?
Example: Singleton is Singleton
Activity is A
Service S
Service S has a handle to Singleton. S requests Singleton to launch Activity. Activity calls operational methods defined in Singleton.
I have several Singletons in my application which encapsulate various operations for a functional area. So Activities will interact with various Singletons to perform various operations.
I don't think there is an issue with this approach. I use singletons quite often and never had any problems. You just need to keep in mind that android might remove the singleton instance when it needs the memory, so you need to check for null every time you get the singleton instance.
Usually it won't introduce the issue. The only case You could expect it - using service running in separate process (service has android:process attribute defined which starts with '.'). In that case You'll simply has two instances of the singleton - one for each process.
What is better and right, use singlenton object that bind to the service on start app, or binding to service and unbinding from service in every activitiy, that use it?
To bind to a service you need a context. If you implement a singleton object and base its context on an activity you will have trouble as the activity may not live for the duration that you access the service.
If you take the context from the application you will run into the trouble of establishing when to disconnect from the service and may get memory leaks / unnecessary use of memory.
I would recommend binding to the service per activity but use a inheritence-scheme to only have to write the code once.
Best of luck!