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 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 creating 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-server architecture let's say, a request is made from MainActivity to access the method in LocalService class.
 
A response generated in the 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.
 
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.     @Override    
    29.     protected void onCreate(Bundle savedInstanceState) {    
    30.         super.onCreate(savedInstanceState);    
    31.         setContentView(R.layout.activity_main);    
    32.         mButton = (Button) findViewById(R.id.button);    
    33.         fetchDataTextView = (TextView) findViewById(R.id.textView);    
    34.     
    35.         mButton.setOnClickListener(new View.OnClickListener() {    
    36.             @Override    
    37.             public void onClick(View v) {    
    38.                 fetchDataTextView.setVisibility(View.VISIBLE);    
    39.                 onButtonClick(v);    
    40.             }    
    41.         });    
    42.     }    
    43.     
    44.     @Override    
    45.     protected void onStart() {    
    46.         super.onStart();    
    47.         // Bind to LocalService    
    48.         Intent intent = new Intent(this, LocalService.class);    
    49.         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);    
    50.     }    
    51.     
    52.     @Override    
    53.     protected void onStop() {    
    54.         super.onStop();    
    55.         // Unbind from the service    
    56.         if (mBound) {    
    57.             unbindService(mConnection);    
    58.             mBound = false;    
    59.         }    
    60.     }    
    61.     
    62.     public void onButtonClick(View v) {    
    63.         if (mBound) {    
    64.     
    65.             Message msg = Message.obtain(null, LocalService.FETCH_DATA_FROM_API, 00);    
    66.             msg.replyTo = replyMessenger;    
    67.             try {    
    68.                 mService.send(msg);    
    69.             } catch (RemoteException e) {    
    70.                 e.printStackTrace();    
    71.             }    
    72.         }    
    73.     }    
    74.     
    75.     /**  
    76.      * Defines callbacks for service binding, passed to bindService()  
    77.      */    
    78.     private ServiceConnection mConnection = new ServiceConnection() {    
    79.     
    80.         @Override    
    81.         public void onServiceConnected(ComponentName className,    
    82.                                        IBinder service) {    
    83.     
    84.             Toast.makeText(MainActivity.this"connected", Toast.LENGTH_SHORT).show();    
    85.             mService = new Messenger(service);    
    86.             mBound = true;    
    87.         }    
    88.     
    89.         @Override    
    90.         public void onServiceDisconnected(ComponentName arg0) {    
    91.             mService = null;    
    92.             mBound = false;    
    93.         }    
    94.     };    
    95.     
    96.     Messenger replyMessenger = new Messenger(new HandlerReplyMsg());    
    97.     
    98.     // handler for message from service    
    99.     
    100.     class HandlerReplyMsg extends Handler {    
    101.         @Override    
    102.         public void handleMessage(Message msg) {    
    103.             super.handleMessage(msg);    
    104.             String recdMessage = msg.obj.toString(); //msg received from service    
    105.             Toast.makeText(MainActivity.this"Response Fetched", Toast.LENGTH_LONG).show();    
    106.             fetchDataTextView.setText(String.valueOf(recdMessage));    
    107.         }    
    108.     }    
    109. }   
      Here, we can see the scenario is completely different to send and receive data between service and activity. Both sides 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.     @Override    
      31.     public IBinder onBind(Intent intent) {    
      32.         Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_LONG).show();    
      33.         return mMessenger.getBinder();    
      34.     }    
      35.     
      36.     /**  
      37.      * Handler of incoming messages from clients.  
      38.      */    
      39.     class IncomingHandler extends Handler {    
      40.         @Override    
      41.         public void handleMessage(Message msg) {    
      42.             switch (msg.what) {    
      43.                 case FETCH_DATA_FROM_API:    
      44.                   //  Bundle bundle = msg.getData();    
      45.                     Toast.makeText(LocalService.this,"Request Recieved",Toast.LENGTH_SHORT).show();    
      46.                     replyMessanger = msg.replyTo;    
      47.                     getDataFromAPI();    
      48.                     break;    
      49.                 default:    
      50.                     super.handleMessage(msg);    
      51.             }    
      52.         }    
      53.     }    
      54.     final Messenger mMessenger = new Messenger(new IncomingHandler());    
      55.     /**  
      56.      * method for clients  
      57.      */    
      58.     public void getDataFromAPI() {    
      59.     
      60.         String url = "http://api.androidhive.info/contacts/";    
      61.         StringRequest sr = null;    
      62.         sr = new StringRequest(Request.Method.GET, url,    
      63.                 new Response.Listener<String>() {    
      64.                     @Override    
      65.                     public void onResponse(String response) {    
      66.                         if (response != null) {    
      67.                             responseData = response.toString();    
      68.                             if (replyMessanger != null)    
      69.                                 try {    
      70.                                     Message message = new Message();    
      71.                                     message.obj = responseData;    
      72.                                     replyMessanger.send(message);//replying / sending msg to activity    
      73.                                 } catch (RemoteException e) {    
      74.                                     e.printStackTrace();    
      75.                                 }    
      76.                         }    
      77.                     }    
      78.                 }, new Response.ErrorListener() {    
      79.     
      80.             @Override    
      81.             public void onErrorResponse(VolleyError error) {    
      82.                 Log.e("volleyerror", error.toString());    
      83.     
      84.             }    
      85.         });    
      86.         VolleySingleton.getInstance(this).getRequestQueue().add(sr);    
      87.     }    
      88.     
      89. }  
      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 received in handleMessage(), a method called there is getDataFromApi() which returns 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 the 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