Binding Service To Activity - Part Two

Introduction

As in my previous article we have learned the basics of Services in Android and how to create them using startService() method. Now in this article we will learn about binding a service to an activity, say MainActivity in our article.

What is bound service?

According to the Google's Android docs "A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC)".

Now you are wondering how it could be a client and server architecture. Let's take an activity say, MainActivity in our case, or any other activity you people can take, MainActivity communicates with a class say a LocalService and this class extends the Android's Service class.

  • A request is made from MainActivity to access the method in LocalService class.
  • A response generated in LocalService class can be forwarded to MainActivity.
Ways to create Bound Services
  • Extending the Binder Class
  • Using a Messenger Class
  • Android Interface Definition Language (AIDL)
Using Binder Class

Now, In this Article we will focus only on the first one, that is extending the Binder class.

Some steps to do to establish communication with the service class, are as follows:
  • create an instance of Binder in service class that:

    1. contains public methods that the client can call.
    2. it can returns the current Service instance, by having service class instance we can call public methods.
    3. or, returns an instance of another class hosted by the service with public methods the client can call.
  • Return this instance of Binder from the onBind() callback method.
  • In the client, receive the Binder from the onServiceConnected() method as shown in the code below and make calls to the bound service using the methods provided.
Lets have a look at code below activity_main.xml,
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:paddingBottom="@dimen/activity_vertical_margin"  
  7.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  8.     android:paddingRight="@dimen/activity_horizontal_margin"  
  9.     android:paddingTop="@dimen/activity_vertical_margin"  
  10.     tools:context="com.example.gkumar.examplebindservice.MainActivity">  
  11.   
  12.     <TextView  
  13.         android:layout_width="wrap_content"  
  14.         android:layout_height="wrap_content"  
  15.         android:text="Fetching Result from Service..."  
  16.         android:id="@+id/textView"  
  17.         android:layout_marginTop="116dp"  
  18.         android:layout_below="@+id/button"  
  19.         android:layout_centerHorizontal="true"  
  20.         android:visibility="invisible"/>  
  21.   
  22.     <Button  
  23.         style="?android:attr/buttonStyleSmall"  
  24.         android:layout_width="150dp"  
  25.         android:layout_height="wrap_content"  
  26.         android:text="Fetch Data"  
  27.         android:id="@+id/button"  
  28.         android:layout_alignParentTop="true"  
  29.         android:layout_centerHorizontal="true" />  
  30.   
  31. </RelativeLayout>  
You can see we have created a button and textview. On the click of the button we will call the public method from service class and will set the response in that textview.

Now find these views created above in MainActivity.java as given below.
  1. package com.example.gkumar.examplebindservice;  
  2.   
  3. import android.content.BroadcastReceiver;  
  4. import android.content.ComponentName;  
  5. import android.content.Context;  
  6. import android.content.Intent;  
  7. import android.content.IntentFilter;  
  8. import android.content.ServiceConnection;  
  9. import android.os.IBinder;  
  10. import android.support.v7.app.AppCompatActivity;  
  11. import android.os.Bundle;  
  12. import android.view.View;  
  13. import android.widget.Button;  
  14. import android.widget.TextView;  
  15. import android.widget.Toast;  
  16.   
  17. public class MainActivity extends AppCompatActivity {  
  18.     LocalService mService;  
  19.     boolean mBound = false;  
  20.     TextView fetchedText;  
  21.     Button mButton;  
  22.     MyReceiver mReciver;  
  23.   
  24.     @Override  
  25.     protected void onCreate(Bundle savedInstanceState) {  
  26.         super.onCreate(savedInstanceState);  
  27.         setContentView(R.layout.activity_main);  
  28.         mButton = (Button) findViewById(R.id.button);  
  29.         fetchedText = (TextView) findViewById(R.id.textView);  
  30.         IntentFilter intentFilter = new IntentFilter();  
  31.         intentFilter.addAction(LocalService.MY_ACTION);  
  32.         mReciver = new MyReceiver();  
  33.         registerReceiver(mReciver,intentFilter);  
  34.         mButton.setOnClickListener(new View.OnClickListener() {  
  35.             @Override  
  36.             public void onClick(View v) {  
  37.                 fetchedText.setVisibility(View.VISIBLE);  
  38.                 onButtonClick(v);  
  39.             }  
  40.         });  
  41.     }  
  42.   
  43.   
  44.     @Override  
  45.     protected void onStart() {  
  46.         super.onStart();  
  47.         Intent intent = new Intent(this, LocalService.class);  
  48.         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  
  49.     }  
  50.   
  51.     @Override  
  52.     protected void onStop() {  
  53.         super.onStop();  
  54.         unregisterReceiver(mReciver);  
  55.         if (mBound) {  
  56.             unbindService(mConnection);  
  57.             mBound = false;  
  58.         }  
  59.   
  60.     }  
  61.   
  62.     public void onButtonClick(View v) {  
  63.         if (mBound) {  
  64.             mService.getDataFromAPI();  
  65.         }  
  66.     }  
  67.   
  68.     /** 
  69.      * Defines callbacks for service binding, passed to bindService() 
  70.      */  
  71.     private ServiceConnection mConnection = new ServiceConnection() {  
  72.   
  73.         @Override  
  74.         public void onServiceConnected(ComponentName className,  
  75.                                        IBinder service) {  
  76.   
  77.             Toast.makeText(MainActivity.this"connected with service", Toast.LENGTH_LONG).show();  
  78.             // We've bound to LocalService, cast the IBinder and get LocalService instance  
  79.             LocalService.LocalBinder binder = (LocalService.LocalBinder) service;  
  80.             mService = binder.getService();  
  81.             mBound = true;  
  82.         }  
  83.   
  84.         @Override  
  85.         public void onServiceDisconnected(ComponentName arg0) {  
  86.             mBound = false;  
  87.         }  
  88.     };  
  89.     private class MyReceiver extends BroadcastReceiver {  
  90.   
  91.         @Override  
  92.         public void onReceive(Context arg0, Intent arg1) {  
  93.             // TODO Auto-generated method stub  
  94.   
  95.             String datapassed = arg1.getStringExtra(LocalService.FETCHIG_DATA);  
  96.   
  97.             Toast.makeText(MainActivity.this,"successful response fetched from API",Toast.LENGTH_LONG).show();  
  98.   
  99.             fetchedText.setText(String.valueOf(datapassed));  
  100.   
  101.         }  
  102.   
  103.     }  
  104. }  
BroadCastReceiver is used to receive data and notifies MainActivity as well, after broadcasting from LocalService class, the fetched response from the API will be send back from service to MainActivity and received in onReceive() method of BroadCastReceiver . Let's have LocalService class code in which data fetching from API.

LocalService.java
  1. package com.example.gkumar.examplebindservice;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.Binder;  
  6. import android.os.IBinder;  
  7. import android.util.Log;  
  8. import com.android.volley.Request;  
  9. import com.android.volley.Response;  
  10. import com.android.volley.VolleyError;  
  11. import com.android.volley.toolbox.StringRequest;  
  12.   
  13. /** 
  14.  * Created by gkumar on 4/11/2016. 
  15.  */  
  16. public class LocalService extends Service {  
  17.     public final static String MY_ACTION = "MY_ACTION";  
  18.     public final static String FETCHIG_DATA = "fetchingapidata";  
  19.   
  20.     private final IBinder mBinder = new LocalBinder();  
  21.   
  22.   
  23.     public class LocalBinder extends Binder {  
  24.         LocalService getService() {  
  25.             // Return this instance of LocalService so clients can call public methods  
  26.             return LocalService.this;  
  27.         }  
  28.     }  
  29.   
  30.     @Override  
  31.     public IBinder onBind(Intent intent) {  
  32.         return mBinder;  
  33.     }  
  34.   
  35.     /** 
  36.      * method for clients 
  37.      */  
  38.   
  39.   
  40.     public void getDataFromAPI() {  
  41.   
  42.         String url = "http://theappguruz.in/php/DemoJSON/api/user/contacts";  
  43.         StringRequest sr = null;  
  44.         sr = new StringRequest(Request.Method.GET, url,  
  45.                 new Response.Listener<String>() {  
  46.                     @Override  
  47.                     public void onResponse(String response) {  
  48.                         if (response != null) {  
  49.   
  50.                             Intent intent = new Intent();  
  51.                             intent.setAction(MY_ACTION);  
  52.                             intent.putExtra(FETCHIG_DATA, response.toString());  
  53.                             sendBroadcast(intent);  
  54.   
  55.                         }  
  56.                     }  
  57.                 }, new Response.ErrorListener() {  
  58.   
  59.             @Override  
  60.             public void onErrorResponse(VolleyError error) {  
  61.   
  62.             }  
  63.         });  
  64.         VolleySingleton.getInstance(this).getRequestQueue().add(sr);  
  65.   
  66.     }  
  67.   
  68. }  
Now you are wondering if that data is fetched using Google's Volley Library. Volley is the most efficient way to fetch data from API and I am going to provide you the singleton class code of volley and build.gradle as well. So you will easily run entire code written above.

VolleySingleton.java

This code will let you use the features of volley library and add gradle dependencies of volley to your build.gradle as provided below this code.
  1. package com.example.gkumar.examplebindservice;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Bitmap;  
  5. import android.support.v4.util.LruCache;  
  6. import com.android.volley.RequestQueue;  
  7. import com.android.volley.toolbox.ImageLoader;  
  8. import com.android.volley.toolbox.Volley;  
  9.   
  10. public class VolleySingleton {  
  11.     private static VolleySingleton mInstance = null;  
  12.     private RequestQueue mRequestQueue;  
  13.     private ImageLoader mImageLoader;  
  14.    
  15.     private VolleySingleton(Context context){  
  16.         mRequestQueue = Volley.newRequestQueue(context);  
  17.         mImageLoader = new ImageLoader(this.mRequestQueue, new ImageLoader.ImageCache() {  
  18.             private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);  
  19.             public void putBitmap(String url, Bitmap bitmap) {  
  20.                 mCache.put(url, bitmap);  
  21.             }  
  22.             public Bitmap getBitmap(String url) {  
  23.                 return mCache.get(url);  
  24.             }  
  25.         });  
  26.     }  
  27.    
  28.     public static VolleySingleton getInstance(Context context){  
  29.         if(mInstance == null){  
  30.             mInstance = new VolleySingleton(context);  
  31.         }  
  32.         return mInstance;  
  33.     }  
  34.    
  35.     public RequestQueue getRequestQueue(){  
  36.         return this.mRequestQueue;  
  37.     }  
  38.   
  39.       
  40. }  
Build.gradle (app)
  1. apply plugin: 'com.android.application'  
  2.   
  3. android {  
  4.     compileSdkVersion 23  
  5.     buildToolsVersion "23.0.2"  
  6.   
  7.     defaultConfig {  
  8.         applicationId "com.example.gkumar.examplebindservice"  
  9.         minSdkVersion 15  
  10.         targetSdkVersion 23  
  11.         versionCode 1  
  12.         versionName "1.0"  
  13.     }  
  14.     buildTypes {  
  15.         release {  
  16.             minifyEnabled false  
  17.             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
  18.         }  
  19.     }  
  20. }  
  21.   
  22. dependencies {  
  23.     compile fileTree(dir: 'libs', include: ['*.jar'])  
  24.     testCompile 'junit:junit:4.12'  
  25.     compile 'com.android.support:appcompat-v7:23.1.1'  
  26.     compile 'com.android.volley:volley:1.0.0'  
  27.   
  28. }  
Most important is AndroidManifest.xml file and don't forget to register the service in service tag as shown below and permission to access internet is must without it you cant fetch data from network. put this <uses-permission android:name="android.permission.INTERNET" /> in code as we have done.
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.gkumar.examplebindservice">  
  4.     <uses-permission android:name="android.permission.INTERNET" />  
  5.     <application  
  6.         android:allowBackup="true"  
  7.         android:icon="@mipmap/ic_launcher"  
  8.         android:label="@string/app_name"  
  9.         android:supportsRtl="true"  
  10.         android:theme="@style/AppTheme">  
  11.         <activity android:name=".MainActivity"  
  12.             android:screenOrientation="portrait">  
  13.             <intent-filter>  
  14.                 <action android:name="android.intent.action.MAIN" />  
  15.   
  16.                 <category android:name="android.intent.category.LAUNCHER" />  
  17.             </intent-filter>  
  18.         </activity>  
  19.         <service  
  20.             android:name="com.example.gkumar.examplebindservice.LocalService"  
  21.             android:enabled="true"  
  22.             android:exported="false" />  
  23.     </application>  
  24.   
  25. </manifest>  
Running the Application

You can see a button after and a toast show activity connected with service.



Now click on the Button you will see data has been fetching.


Response set on the textview as shown



Summary

In this article we have learned how to bind service with an activity and send data back to activity from service. In the next article we will see binding activity with service using messenger.
 
Read more articles on Android:

Up Next
    Ebook Download
    View all
    Learn
    View all