In my previous tutorials I have been talking about Services in Android, showcasing basic functions of a service. This tutorial also shows Android service class, but it revolves around a specific feature of this class i.e binding of service to an activity. It also briefly explains the features associated with Android bind service type. Although if you are not clear on what android bind services are, here’s a brief explanation. A bound service is a type of service which can bind with one or more application components like activities and return the results back to them.
As I explained in my previous tutorials that in Android services are used for long running operations, presumably never ending operations. Here in this Bound Service Example In Android tutorial I would also show a never ending service. But talking about services here, I would like to say that service is an Android component which should be used only when you don’t have a requirement to display something on user interface. Most of the times, services are used for long running network operations. If you want to explore more on services have a look at some of my tutorials listed below:
Android Service: Return Data To Activity
While working with Android services, there comes a situation where we would want the service to communicate with an activity. To accomplish this task one has to bind a service to an activity, this type of service is called an android bound service. After a service is bound to an activity one can return the results back to the calling activity. Here in this tutorial I would start a timer service which would keep counting a timer from the start of service. Then I will bind this service to the same activity, which would make this a bound service. Why I started a service and then bind it? will answer this later in the tutorial. For now lets start with some code:
<?xml version="1.0" encoding="utf-8"?> <manifest package="com.truiton.boundservice" xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0"> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <service android:name="com.truiton.boundservice.BoundService"> </service> </application> </manifest>
In the above piece of code you can see that I have defined the service and an activity in the manifest. Moving on lets define the service which will be bound to an activity.
package com.truiton.boundservice; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.os.SystemClock; import android.util.Log; import android.widget.Chronometer; public class BoundService extends Service { private static String LOG_TAG = "BoundService"; private IBinder mBinder = new MyBinder(); private Chronometer mChronometer; @Override public void onCreate() { super.onCreate(); Log.v(LOG_TAG, "in onCreate"); mChronometer = new Chronometer(this); mChronometer.setBase(SystemClock.elapsedRealtime()); mChronometer.start(); } @Override public IBinder onBind(Intent intent) { Log.v(LOG_TAG, "in onBind"); return mBinder; } @Override public void onRebind(Intent intent) { Log.v(LOG_TAG, "in onRebind"); super.onRebind(intent); } @Override public boolean onUnbind(Intent intent) { Log.v(LOG_TAG, "in onUnbind"); return true; } @Override public void onDestroy() { super.onDestroy(); Log.v(LOG_TAG, "in onDestroy"); mChronometer.stop(); } public String getTimestamp() { long elapsedMillis = SystemClock.elapsedRealtime() - mChronometer.getBase(); int hours = (int) (elapsedMillis / 3600000); int minutes = (int) (elapsedMillis - hours * 3600000) / 60000; int seconds = (int) (elapsedMillis - hours * 3600000 - minutes * 60000) / 1000; int millis = (int) (elapsedMillis - hours * 3600000 - minutes * 60000 - seconds * 1000); return hours + ":" + minutes + ":" + seconds + ":" + millis; } public class MyBinder extends Binder { BoundService getService() { return BoundService.this; } } }
Ok the above BoundService
class is the main service class which will bound to an activity. Now since this is a bound service tutorial, in the above class I have tried to create a never ending timer service, as it should be in a real world scenario. If you closely observe the above stated code, you would see that this timer service runs a Chronometer, and returns time-stamp through a public method. Since this method is a public method of BoundService
class it may be accessed only through an object of this class. In-comes the Android Bind Service concepts.
To do this I have created a MyBinder
class which inherits Binder class which in-turn implements IBinder interface. This class has a method which returns the object of this BoundService
class. Though this object any android application component would be able to access public methods of this class.
Now before defining the class which will bind this Android service, lets make a layout for activity:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.truiton.boundservice.MainActivity" > <ImageView android:id="@+id/imageView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="-80dp" android:src="@drawable/truiton_sq" /> <Button android:id="@+id/print_timestamp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="130dp" android:text="Print Timestamp" /> <TextView android:id="@+id/timestamp_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/print_timestamp" android:layout_centerHorizontal="true" android:layout_marginTop="120dp" android:text="" android:textAppearance="?android:attr/textAppearanceLarge" /> <Button android:id="@+id/stop_service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/print_timestamp" android:layout_centerHorizontal="true" android:text="Stop Service" /> </RelativeLayout>
Next have a look at the MainActivity
which will bind the BoundService
class:
package com.truiton.boundservice; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import com.truiton.boundservice.BoundService.MyBinder; public class MainActivity extends AppCompatActivity { BoundService mBoundService; boolean mServiceBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final TextView timestampText = (TextView) findViewById(R.id.timestamp_text); Button printTimestampButton = (Button) findViewById(R.id.print_timestamp); Button stopServiceButon = (Button) findViewById(R.id.stop_service); printTimestampButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mServiceBound) { timestampText.setText(mBoundService.getTimestamp()); } } }); stopServiceButon.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mServiceBound) { unbindService(mServiceConnection); mServiceBound = false; } Intent intent = new Intent(MainActivity.this, BoundService.class); stopService(intent); } }); } @Override protected void onStart() { super.onStart(); Intent intent = new Intent(this, BoundService.class); startService(intent); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); if (mServiceBound) { unbindService(mServiceConnection); mServiceBound = false; } } private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mServiceBound = false; } @Override public void onServiceConnected(ComponentName name, IBinder service) { MyBinder myBinder = (MyBinder) service; mBoundService = myBinder.getService(); mServiceBound = true; } }; }
All of this should give an output like this :
Above MainActivity
class is the class which starts the BoundService
class and then later on binds to it. Whenever a service is started or bound, first onCreate()
method is called, then the onStartCommand()
or onBind()
method is called according to the situation. But here in this Bound Service Example In Android tutorial first the onStartCommand()
method is called then the onBind()
method is called. Although if you closely observe I have not implemented the onStartCommand()
method, hence its default implementation will be called.
I left off a point above referring to, why I started a service and then created a binding for it. The answer lies in the official documentation that if we bind a service without starting it, the bound service would exist only while the binding application component is active. In other words if a service is not started, only bound to an activity then it will exist till the activity exists. In most cases and in this case too we need a service to remain active even when the activity is not present, hence the service is started first then its bound to an activity. Same is stated in the documentation for Context.BIND_AUTO_CREATE the flag used for binding the service.
Coming back to our MainActivity
, here you can see that ServiceConnection class is used to establish or bind a connection to the service, through which an object of class is returned. Now whenever an operation on service is to be performed this object reference is used. Like in this Bound Service Example In Android tutorial mBoundService.getTimestamp()
method is used to get the time-stamp from the service.
Android Service: onUnbind Method
Okay this method in the Android bound service implementation is sort of special, as it can control the life-cycle of a service. This method may seem harmless but can do a great amount of damage to your code if not used properly. In regular flow this method is called when the bound application component like an activity unbinds the service by calling unbindService()
method.
Android Service onUnbind method can alter the flow for Android bound service on the basis of its return value, it can either be true
or false
.
- For
true
it signifies that if a binding is created again for this service, instead ofonBind
method,onRebind
method would be called. - If
false
is returned then bothonBind
andonUnbind
methods are called only once. In other words if a new binding is created for this case none of these methods would be called. For each subsequent binding, same object of the service will be returned from the Android Binder class when service is connected.
Only one call to Android service onBind Method
Although if you were reading this Bound Service Example In Android thoroughly you might have got this point till now. That service’s onBind
method would be called only once in both the cases of onUnbind
method. So choose wisely according to specs. To view full source code, please have at the link below:
Another important thing that I observed while exploring was that, if a service is bound to an application component, it cannot be stopped until unbind is called from that component. If a service has multiple bindings then all the bindings have to be removed, only then your service may stop. Hope this helped.
Born in New Delhi, India. A software engineer by profession, an android enthusiast and an evangelist. My motive here is to create a group of skilled developers, who can develop something new and good. Reason being programming is my passion, and also it feels good to make a device do something you want. In a very short span of time professionally I have worked with many tech firms. As of now too, I am employed as a senior engineer in a leading tech company. In total I may have worked on more than 20 projects professionally, and whenever I get spare time I share my thoughts here at Truiton.
Nice tutorial
Thank for your posting, and clearly understand bounded service in android
Good work, terrible english.
Hi John,
English isn’t my best language. Android/Java is.
But still trying to improve.
-Mohit
Dont mind others..ur technical knowledge is really good.Great tutorial..awesome work buddy
Thanks Mohit – the example helped me greatly, particularly in gaining a better understanding in the order in which the events are fired.
I posted my reply here, as I agree with Srini’s comment.
Excellent example, thank you so much!
And ignore the haters, your English is better than 90% of the people I have worked with, both ESLs and EFLs.
Man thank you
Nice Tutorial, easy to understand. thanks
Mohit sir, thanks a lot for all your tutorials
Thanks a lot, Mohit! Good tutorial!
Why we need bound service?I want to know.
Thank you
Mohit, this is a wonderful tutorial!
Thanks !
Thanks!
How would you bind second activity to service ?
Very well explained, coz I really understood the concept after reading so many articles. Thanks!
Thanks for your tutorial. All tutorials that I’ve read regarding bound services talk about how to call service methods from an activity, which allows communication initiated by the activity.
But can you please explain how you would initiate communication and send data from the service to the activity?
To initiate communication from service you might have to use a
Messenger
to provide the interface for your service. To see a working example please refer to these samples MessengerService.java (service) and MessengerServiceActivities.java (client).