26

I am working on a music player app. I have a main activity which has multiple fragments, each displaying songs on the device album wise, artist wise etc..
I have a music service which handles all the playback and other stuff.
What I'm confused about is the binding of this service with various fragments I have.
Right now I'm binding the main activity and each fragment individually with the service and its working pretty much fine. But I was wondering if this is really the best practice? Is there any way to just bind the main activity with the service and then some how use it in its child fragments?
I maybe missing some very basic concept of activity or fragments or services. So someone please guide me in this regard.
I guess it's more of a conceptual question so any code isn't needed. But still if it's required then please let me know.

EDIT :
My question is: What would be a better way to bind a service with an activity with multiple child fragments(each of which would be using the service)?

Anjani
  • 1,533
  • 3
  • 15
  • 26
  • 5
    Bind it to the activity hosting your fragments. A fragment takes on the context of the host activity, which is accessed with the getActivity() method. You can then interact with the service through the activity. Trying to bind to every fragment and activity is a mess. – Rarw Jun 19 '14 at 14:54
  • @Rarw Thanks for the advice. Is this the only way or are there any alternatives to that? – Anjani Jun 19 '14 at 15:01
  • 2
    I suppose this might help: http://stackoverflow.com/questions/15235773/bind-service-to-fragmentactivity-or-fragment – ata Aug 27 '14 at 15:18

7 Answers7

22

Bind the Service to your activity and not the Fragment. The description of your application, one activity with multiple Fragment that are swapped in and out, makes this the most (and really only) practical approach.

When you bind a Service to an Activity you are tying its lifecycle to that of the Activity. See Bound Services. Each time you add or remove a Fragment in your activity that Fragment is created and destroyed. You do not want to try to link a service to this process because then you would have to create and destroy the service each time a new fragment is created or destroyed.

Instead bind to the host Activity. You can then interact with your host activity from your fragments with an interface to access the bound service or by Intent.

Rarw
  • 7,645
  • 3
  • 28
  • 46
  • Should I create the constructor of Fragments including the instance of the backend Services? – Jeff Bootsholz Jan 31 '16 at 02:46
  • That depends if its essential to your fragment working properly. That's generally my rule when adding something to a constructor. – Rarw Jan 31 '16 at 20:39
  • If you have multiple fragments and each of them binds to the same service, the bound service will stay up until at least one client is bound. If you bind your activity to the service too, you are sure that the service will stay up as long as the activity is. In my experience binding to fragments directly is the best choice, I will post an answer. – Ena May 10 '16 at 15:18
  • 1
    @Ena The question describes an activity a loads/swaps multiple fragments to control functions running in a background service. All the fragments are hosted by the same activity. In this case it makes sense to bind the activity to the service, and then load each fragment in the activity (visually I think of it like an upside down pyramid, the fragment's cannot exist without the middle activity). If I had more than one activity and more than one fragment I would bind the fragments individually for the reason you describe. – Rarw May 11 '16 at 19:40
21

I think the cleaner architecture is to bind directly from the fragment. Regarding the problem outlined in Rarw's answer, you can bind to the service from your activity and from your fragments too. This way you are sure that the service will be there until the activity is not destroyed.

I can see two main advantages in connecting from the fragment:

  1. Service connection is async, so inside the fragment you are never really sure that the service you are getting from the activity is not null. This will lead you at least to some null pointer checks and to some mechanism to refresh the fragment both when it's created and when the service connects (so you are sure you will display the data no matter which of the two happens first).

  2. You do not depend on the particular activity your fragments lives in. To get the service from the activity I think you are doing a cast to the activity specific class. You could create an interface like BoundActivity with a method like getBoundService to obtain the service from it, but I think it's an overhead considering the advantage of point 1. And what if you have multiple services.

UPDATE

Here is a very simple project showing this. https://github.com/ena1106/FragmentBoundServiceExample

Ena
  • 3,481
  • 36
  • 34
  • Yes, your first reason is very true!! I was getting NullPointerExceptions all the time. Especially when the first fragment loads and the activity wasn't bound yet to the service. Thank you for posting the simple project link. I will try binding to fragments immediately. Hope it works! ;) – melledijkstra Dec 12 '16 at 10:51
  • I think this should be the accepted answer. The answer to these kinds of question is "It depends". So I believe if it makes sense to place it inside a fragment over the activity definitely do it. – Archie G. Quiñones Jan 22 '19 at 08:20
0

You can access your activity from a fragment by getActivity()

Alexander Kulyakhtin
  • 47,782
  • 38
  • 107
  • 158
  • Thanks for a quick reply. I am aware of this function. But what I'm trying to ask is whether it's advisable to bind the service with only the main activity and use getActivity() in fragments to use that service? Or should I bind it with all of activity and fragments individually? – Anjani Jun 19 '14 at 14:50
  • I would bind to as few entities as possible although I have no idea if it's advisable or not. – Alexander Kulyakhtin Jun 19 '14 at 15:21
  • getActivity() can return null. Better to use onAttach(), ref http://stackoverflow.com/a/11743728/763176 – saxman Oct 21 '16 at 17:13
  • getActivity will return any parent activity the fragment is being used in. so it doesn't guarantee what type the activity is. – Arturs Vancans Feb 12 '17 at 00:48
0

you can tray using the event bus pattern with this library , eventbus publish/subscribe pattern.https://github.com/greenrobot/EventBus check the project site for more information.

you can send events from/to service to active or fragments

ingyesid
  • 2,864
  • 2
  • 23
  • 21
  • Though I don't really need so much of functionality, but I'll for sure have a look at this library. Thanks. – Anjani Jun 20 '14 at 07:22
0

IF you need to get some data from your service to your fragment at the beginning of the fragment lifecycle, the onServiceConnected on activity could not be called yet, mainly when you rotate your device, and you'll get a NPE. I think is a good idea let fragment make his own connections since the service is started with startService() and not with bindService().

Informatheus
  • 1,025
  • 1
  • 9
  • 20
0

I bind service in My Host Activity,and pass Ibinder's object by Bundle which is setted in arguments.

and my code may like this:

private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        //put service in bundle
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};
fantianwen
  • 21
  • 3
0

The only method I have found to be reliable is to use a loader in Fragment:

  1. create a Loader in the fragment
  2. use the context of the Loader (set to activity in initLoader at when the Fragment's onCreate is called)
  3. bind the service in onStartLoading, using a ServiceConnection which calls forceLoad() as soon as the service is bound
  4. optionally register callbacks in onStartLoading/onStopLoading
  5. unbind the service in onStopLoading
u8188526
  • 171
  • 2
  • 5