Bound Service Using Messenger In Android: Part Three

Introduction

As in the previous article we have learned about binding the service to an activity using extending the Binder class. As we had listed three methods in the previous article that an activity could communicate with. like using Binder class and using messenger and AIDL. Before that, let's have a look at previous articles of the series,

Messenger is used to create inter process communication (IPC). There are certain steps to create that type of communication in which communication is bidirectional; that is, between two processes.

This is also a client sever architecture let's say, a request is made from MainActivity to access the method in LocalService class.
A response generated in LocalService class can be forwarded to MainActivity.

Steps to use Messenger :
  • The service class will implement a Handler that receives a callback for each call from a client(MainActivity).
  • In this case using Handler to create a Messenger object (which is a reference to the Handler).
  • The Messenger creates an IBinder that the service returns to clients from onBind().
  • Client Activity use the IBinder to instantiate the Messenger (that references the service's Handler), which the client uses to send Message objects to the service.
The service will receive all the messages from client activity in the handleMessage() method of IncomingHandler class we have created that extends Handler class. Again as seen previously,  service connection establishment is necessary and initializes the Messenger class object.

Let's hover around the code.

activity_main.xml


Creating button and text view to initiate communication and setting data respectively.
  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.servicebindermessanger.MainActivity">  
  11.   
  12.     <Button  
  13.         android:layout_width="wrap_content"  
  14.         android:layout_height="wrap_content"  
  15.         android:text="Get Data"  
  16.         android:id="@+id/button"  
  17.         android:layout_alignParentTop="true"  
  18.         android:layout_centerHorizontal="true" />  
  19.     <TextView  
  20.         android:id="@+id/textView"  
  21.         android:layout_width="wrap_content"  
  22.         android:layout_height="wrap_content"  
  23.         android:text="Fetching Data From Api..."  
  24.         android:layout_below="@+id/button"  
  25.         android:layout_centerHorizontal="true"  
  26.         android:layout_marginTop="82dp"  
  27.         android:visibility="invisible"/>  
  28. </RelativeLayout>  
Now find these views created above in MainActivity.java as given below.
  1. package com.example.gkumar.servicebindermessanger;  
  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.Handler;  
  10. import android.os.IBinder;  
  11. import android.os.Message;  
  12. import android.os.Messenger;  
  13. import android.os.RemoteException;  
  14. import android.support.v7.app.AppCompatActivity;  
  15. import android.os.Bundle;  
  16. import android.view.View;  
  17. import android.widget.Button;  
  18. import android.widget.TextView;  
  19. import android.widget.Toast;  
  20.   
  21. public class MainActivity extends AppCompatActivity {  
  22.     //  LocalService mService;  
  23.     Messenger mService = null;  
  24.     boolean mBound = false;  
  25.     TextView fetchDataTextView;  
  26.     Button mButton;  
  27.   
  28.   
  29.     @Override  
  30.     protected void onCreate(Bundle savedInstanceState) {  
  31.         super.onCreate(savedInstanceState);  
  32.         setContentView(R.layout.activity_main);  
  33.         mButton = (Button) findViewById(R.id.button);  
  34.         fetchDataTextView = (TextView) findViewById(R.id.textView);  
  35.   
  36.         mButton.setOnClickListener(new View.OnClickListener() {  
  37.             @Override  
  38.             public void onClick(View v) {  
  39.                 fetchDataTextView.setVisibility(View.VISIBLE);  
  40.                 onButtonClick(v);  
  41.             }  
  42.         });  
  43.     }  
  44.   
  45.   
  46.     @Override  
  47.     protected void onStart() {  
  48.         super.onStart();  
  49.         // Bind to LocalService  
  50.         Intent intent = new Intent(this, LocalService.class);  
  51.         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);  
  52.     }  
  53.   
  54.     @Override  
  55.     protected void onStop() {  
  56.         super.onStop();  
  57.         // Unbind from the service  
  58.         if (mBound) {  
  59.             unbindService(mConnection);  
  60.             mBound = false;  
  61.         }  
  62.     }  
  63.   
  64.     public void onButtonClick(View v) {  
  65.         if (mBound) {  
  66.   
  67.             Message msg = Message.obtain(null, LocalService.FETCH_DATA_FROM_API, 00);  
  68.             msg.replyTo = replyMessenger;  
  69.             try {  
  70.                 mService.send(msg);  
  71.             } catch (RemoteException e) {  
  72.                 e.printStackTrace();  
  73.             }  
  74.         }  
  75.     }  
  76.   
  77.     /** 
  78.      * Defines callbacks for service binding, passed to bindService() 
  79.      */  
  80.     private ServiceConnection mConnection = new ServiceConnection() {  
  81.   
  82.         @Override  
  83.         public void onServiceConnected(ComponentName className,  
  84.                                        IBinder service) {  
  85.   
  86.             Toast.makeText(MainActivity.this"connected", Toast.LENGTH_SHORT).show();  
  87.             mService = new Messenger(service);  
  88.             mBound = true;  
  89.         }  
  90.   
  91.         @Override  
  92.         public void onServiceDisconnected(ComponentName arg0) {  
  93.             mService = null;  
  94.             mBound = false;  
  95.         }  
  96.     };  
  97.   
  98.   
  99.     Messenger replyMessenger = new Messenger(new HandlerReplyMsg());  
  100.   
  101.     // handler for message from service  
  102.   
  103.     class HandlerReplyMsg extends Handler {  
  104.         @Override  
  105.         public void handleMessage(Message msg) {  
  106.             super.handleMessage(msg);  
  107.             String recdMessage = msg.obj.toString(); //msg received from service  
  108.             Toast.makeText(MainActivity.this"Response Fetched", Toast.LENGTH_LONG).show();  
  109.             fetchDataTextView.setText(String.valueOf(recdMessage));  
  110.         }  
  111.     }  
  112. }  

Here, we can see the scenario is completely different to send and receive data between service and activity. Both side are using handlers to handle communications bidirectional information interchange. See the code written; in onButtonClick() method we are just sending the request to the Local Service class using the messenger.

Now you can see a handler for handling of the replied messages or response from service class. In this handleMessage() just getting message and String type data received and set in the text view simply.

Let's have a look at our service part, say LocalService.java :
  1. package com.example.gkumar.servicebindermessanger;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.Binder;  
  6. import android.os.Bundle;  
  7. import android.os.Handler;  
  8. import android.os.IBinder;  
  9. import android.os.Message;  
  10. import android.os.Messenger;  
  11. import android.os.RemoteException;  
  12. import android.util.Log;  
  13. import android.widget.Toast;  
  14.   
  15. import com.android.volley.Request;  
  16. import com.android.volley.Response;  
  17. import com.android.volley.VolleyError;  
  18. import com.android.volley.toolbox.StringRequest;  
  19.   
  20. import java.util.Random;  
  21.   
  22. /** 
  23.  * Created by gkumar on 4/11/2016. 
  24.  */  
  25. public class LocalService extends Service {  
  26.     Messenger replyMessanger;  
  27.     static final int FETCH_DATA_FROM_API = 1;  
  28.     public static String responseData;  
  29.   
  30.   
  31.     @Override  
  32.     public IBinder onBind(Intent intent) {  
  33.         Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_LONG).show();  
  34.         return mMessenger.getBinder();  
  35.     }  
  36.   
  37.   
  38.     /** 
  39.      * Handler of incoming messages from clients. 
  40.      */  
  41.     class IncomingHandler extends Handler {  
  42.         @Override  
  43.         public void handleMessage(Message msg) {  
  44.             switch (msg.what) {  
  45.                 case FETCH_DATA_FROM_API:  
  46.                   //  Bundle bundle = msg.getData();  
  47.                     Toast.makeText(LocalService.this,"Request Recieved",Toast.LENGTH_SHORT).show();  
  48.                     replyMessanger = msg.replyTo;  
  49.                     getDataFromAPI();  
  50.                     break;  
  51.                 default:  
  52.                     super.handleMessage(msg);  
  53.             }  
  54.         }  
  55.     }  
  56.     final Messenger mMessenger = new Messenger(new IncomingHandler());  
  57.     /** 
  58.      * method for clients 
  59.      */  
  60.     public void getDataFromAPI() {  
  61.   
  62.         String url = "http://api.androidhive.info/contacts/";  
  63.         StringRequest sr = null;  
  64.         sr = new StringRequest(Request.Method.GET, url,  
  65.                 new Response.Listener<String>() {  
  66.                     @Override  
  67.                     public void onResponse(String response) {  
  68.                         if (response != null) {  
  69.                             responseData = response.toString();  
  70.                             if (replyMessanger != null)  
  71.                                 try {  
  72.                                     Message message = new Message();  
  73.                                     message.obj = responseData;  
  74.                                     replyMessanger.send(message);//replying / sending msg to activity  
  75.                                 } catch (RemoteException e) {  
  76.                                     e.printStackTrace();  
  77.                                 }  
  78.                         }  
  79.                     }  
  80.                 }, new Response.ErrorListener() {  
  81.   
  82.             @Override  
  83.             public void onErrorResponse(VolleyError error) {  
  84.                 Log.e("volleyerror", error.toString());  
  85.   
  86.             }  
  87.         });  
  88.         VolleySingleton.getInstance(this).getRequestQueue().add(sr);  
  89.   
  90.     }  
  91.   
  92.   
  93. }  

Let's analyze this code before starting and request received in handleMessages() of IncomingHandler we can see that in the onBind() method returns the messenger class object to MainActivity then only it gets bound. Now request is recieved in handleMessage(), a method called there is getDataFromApi() which return a String response and data send back to MainActivity via Messenger object.

Don't Forget to add following code to Manifest file.

Add permission to Internet and register the service as well.
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.gkumar.servicebindermessanger">  
  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.             <intent-filter>  
  13.                 <action android:name="android.intent.action.MAIN" />  
  14.   
  15.                 <category android:name="android.intent.category.LAUNCHER" />  
  16.             </intent-filter>  
  17.         </activity>  
  18.         <service  
  19.             android:name="com.example.gkumar.servicebindermessanger.LocalService"  
  20.             android:enabled="true"  
  21.             android:exported="false"  
  22.             />  
  23.   
  24.     </application>  
  25.   
  26. </manifest>  

Implementation of Android's volley Library

Put this code as it is will help to create volley request and fetching response from API.

VolleySingleton.java
  1. package com.example.gkumar.servicebindermessanger;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Bitmap;  
  5. import android.support.v4.util.LruCache;  
  6.   
  7. import com.android.volley.RequestQueue;  
  8. import com.android.volley.toolbox.ImageLoader;  
  9. import com.android.volley.toolbox.Volley;  
  10.   
  11. public class VolleySingleton {  
  12.     private static VolleySingleton mInstance = null;  
  13.     private RequestQueue mRequestQueue;  
  14.     private ImageLoader mImageLoader;  
  15.    
  16.     private VolleySingleton(Context context){  
  17.         mRequestQueue = Volley.newRequestQueue(context);  
  18.         mImageLoader = new ImageLoader(this.mRequestQueue, new ImageLoader.ImageCache() {  
  19.             private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);  
  20.             public void putBitmap(String url, Bitmap bitmap) {  
  21.                 mCache.put(url, bitmap);  
  22.             }  
  23.             public Bitmap getBitmap(String url) {  
  24.                 return mCache.get(url);  
  25.             }  
  26.         });  
  27.     }  
  28.    
  29.     public static VolleySingleton getInstance(Context context){  
  30.         if(mInstance == null){  
  31.             mInstance = new VolleySingleton(context);  
  32.         }  
  33.         return mInstance;  
  34.     }  
  35.    
  36.     public RequestQueue getRequestQueue(){  
  37.         return this.mRequestQueue;  
  38.     }   
  39.          
  40. }  
build.gradle

Now add gradle dependencies to build.gradle (app) and sync project.
  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.servicebindermessanger"  
  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. }  
Running the Application
  • Initiating the service using clicking the button and see the toast shows binding because onBind() method is called

         

  • Request Received in handleMessage() of handler in LocalService.java Class you can see the toast showing "request received".

         


  • Response Fetched in MainActivity, data received in handleMessage() of MainActivity.java as shown in code above and set it into textview.

        
 
Summary

Now, considering the previous articles, this article is little bit different, this is IPC via messenger. This article shows the use of handlers to enhance communication between service and activity.
Read more articles on Android:

Up Next
    Ebook Download
    View all
    Learn
    View all