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 the startService() method. Now in this article, we will learn about binding service to an activity, say MainActivity in our article.
 

What is bound service?

 
According to 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 to 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, which 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 return 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 sent back from service to MainActivity and received in onReceive() method of BroadCastReceiver. Let's have a 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.     public class LocalBinder extends Binder {    
    23.         LocalService getService() {    
    24.             // Return this instance of LocalService so clients can call public methods    
    25.             return LocalService.this;    
    26.         }    
    27.     }    
    28.     
    29.     @Override    
    30.     public IBinder onBind(Intent intent) {    
    31.         return mBinder;    
    32.     }    
    33.     
    34.     /**  
    35.      * method for clients  
    36.      */    
    37.     public void getDataFromAPI() {    
    38.     
    39.         String url = "http://theappguruz.in/php/DemoJSON/api/user/contacts";    
    40.         StringRequest sr = null;    
    41.         sr = new StringRequest(Request.Method.GET, url,    
    42.                 new Response.Listener<String>() {    
    43.                     @Override    
    44.                     public void onResponse(String response) {    
    45.                         if (response != null) {    
    46.     
    47.                             Intent intent = new Intent();    
    48.                             intent.setAction(MY_ACTION);    
    49.                             intent.putExtra(FETCHIG_DATA, response.toString());    
    50.                             sendBroadcast(intent);    
    51.     
    52.                         }    
    53.                     }    
    54.                 }, new Response.ErrorListener() {    
    55.     
    56.             @Override    
    57.             public void onErrorResponse(VolleyError error) {    
    58.     
    59.             }    
    60.         });    
    61.         VolleySingleton.getInstance(this).getRequestQueue().add(sr);    
    62.     }    
    63.     
    64. }   
      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 the entire code written above.
       
      VolleySingleton.java
       
      This code will let you use the features of the 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. }   
      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 the internet is a must without it you cant fetch data from the 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 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


          Similar Articles