Bound Service Example In Android - Truiton
Skip to content

Bound Service Example In Android

Photo Credit: Francisco Sánchez via Compfight cc

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:

  1.  Android Service and BroadcastReceiver Example
  2.  Android Foreground Service Example 

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 :

Android Bind Service

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.

  1. For true it signifies that if a binding is created again for this service, instead of onBind method, onRebind method would be called.
  2. If false is returned then both onBind and onUnbind 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:

Full Source Code

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.

20 thoughts on “Bound Service Example In Android”

        1. 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.

  1. 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.

  2. 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?

Leave a Reply

Your email address will not be published. Required fields are marked *