How to communicate between Activity and Service using Messaging in Android

In this android programming source code example, we are going to communicate between Activity and Service using Messaging in Android.

You can copy and adopt this source code example to your android project without reinventing the wheel.

Below is a step by step source code to communicate between Activity and Service using Messaging in Android.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".MapAndService.MapAndServiceActivity15">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent">

        <TextView
            android:id="@+id/tvCounter"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Counter"
            android:gravity="center"
            android:layout_gravity="center_horizontal"
            android:textSize="20sp" />

            <Button
                android:id="@+id/btnStart"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Start Service"
                android:layout_marginTop="5dp"
                android:background="@color/colorAccent"
                android:textColor="#ffffff"/>

            <Button
                android:id="@+id/btnStop"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:text="Stop Service"
                android:layout_marginTop="5dp"
                android:background="@color/colorAccent"
                android:textColor="#ffffff"/>
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java

import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

public class MapAndServiceActivity15 extends AppCompatActivity {
    private TextView tvCounter;
    private Button btnStart;
    private Button btnStop;
    private ServiceManager service;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map_and_service15);
        tvCounter = (TextView) findViewById(R.id.tvCounter);
        btnStart = (Button) findViewById(R.id.btnStart);
        btnStop = (Button) findViewById(R.id.btnStop);

        this.service = new ServiceManager(this, Service15.class, new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case Service15.MSG_COUNTER:
                        // Receive counter value from service 1
                        tvCounter.setText("Counter: " + msg.arg1);
                        break;

                    default:
                        super.handleMessage(msg);
                }
            }
        });

        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                service.start();
                Toast.makeText(MapAndServiceActivity15.this, "Service Started", Toast.LENGTH_SHORT).show();
            }
        });

        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                service.stop();
                Toast.makeText(MapAndServiceActivity15.this, "Service Stopped", Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            service.unbind();
        } catch (Throwable t) {
        }
    }

    public class ServiceManager {
        private Class<? extends AbstractService> mServiceClass;
        private Context mActivity;
        private boolean mIsBound;
        private Messenger mService = null;
        private Handler mIncomingHandler = null;
        private final Messenger mMessenger = new Messenger(new IncomingHandler());
        private class IncomingHandler extends Handler {
            @Override
            public void handleMessage(Message msg) {
                if (mIncomingHandler != null) {
                    Log.i("ServiceHandler", "Incoming message. Passing to handler: " + msg);
                    mIncomingHandler.handleMessage(msg);
                }
            }
        }
        private ServiceConnection mConnection = new ServiceConnection() {
            public void onServiceConnected(ComponentName className, IBinder service) {
                mService = new Messenger(service);
                Log.i("ServiceHandler", "Attached.");
                try {
                    Message msg = Message.obtain(null, AbstractService.MSG_REGISTER_CLIENT);
                    msg.replyTo = mMessenger;
                    mService.send(msg);
                } catch (RemoteException e) {
                }
            }
            public void onServiceDisconnected(ComponentName className) {
                mService = null;
                Log.i("ServiceHandler", "Disconnected.");
            }
        };
        public ServiceManager(Context context, Class<? extends AbstractService> serviceClass, Handler incomingHandler) {
            this.mActivity = context;
            this.mServiceClass = serviceClass;
            this.mIncomingHandler = incomingHandler;
            if (isRunning()) {
                doBindService();
            }
        }
        public void start() {
            doStartService();
            doBindService();
        }
        public void stop() {
            doUnbindService();
            doStopService();
        }
        public void unbind() {
            doUnbindService();
        }

        public boolean isRunning() {
            ActivityManager manager = (ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE);
            for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
                if (mServiceClass.getName().equals(service.service.getClassName())) {
                    return true;
                }
            }
            return false;
        }
        public void send(Message msg) throws RemoteException {
            if (mIsBound) {
                if (mService != null) {
                    mService.send(msg);
                }
            }
        }
        private void doStartService() {
            mActivity.startService(new Intent(mActivity, mServiceClass));
        }
        private void doStopService() {
            mActivity.stopService(new Intent(mActivity, mServiceClass));
        }
        private void doBindService() {
            mActivity.bindService(new Intent(mActivity, mServiceClass), mConnection, Context.BIND_AUTO_CREATE);
            mIsBound = true;
        }
        private void doUnbindService() {
            if (mIsBound) {
                if (mService != null) {
                    try {
                        Message msg = Message.obtain(null, AbstractService.MSG_UNREGISTER_CLIENT);
                        msg.replyTo = mMessenger;
                        mService.send(msg);
                    } catch (RemoteException e) {
                    }
                }
                mActivity.unbindService(mConnection);
                mIsBound = false;
                Log.i("ServiceHandler", "Unbinding.");
            }
        }
    }
}

Service15.java

import android.os.Message;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

public class Service15 extends AbstractService {
    public static final int MSG_INCREMENT = 1;
    public static final int MSG_COUNTER = 2;
    private Timer timer = new Timer();
    private int counter = 0, incrementby = 1;

    @Override
    public void onStartService() {
        timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 0, 250L);
    }

    @Override
    public void onStopService() {
        if (timer != null) {timer.cancel();}
        counter=0;
        Log.i("MyService", "Service Stopped.");
    }

    @Override
    public void onReceiveMessage(Message msg) {
        if (msg.what == MSG_INCREMENT) {
            incrementby = msg.arg1;
        }
    }
    private void onTimerTick() {
        try {
            counter += incrementby;
            send(Message.obtain(null, MSG_COUNTER, counter, 0));
        }
        catch (Throwable t) { //you should always ultimately catch all exceptions in timer tasks.
            Log.e("TimerTick", "Timer Tick Failed.", t);
        }
    }
}

AbstractService.java

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;

public abstract class AbstractService extends Service {
    static final int MSG_REGISTER_CLIENT = 9991;
    static final int MSG_UNREGISTER_CLIENT = 9992;
    ArrayList<Messenger> mClients = new ArrayList<Messenger>();
    final Messenger mMessenger = new Messenger(new IncomingHandler());
    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REGISTER_CLIENT:
                    Log.i("MyService", "Client registered: " + msg.replyTo);
                    mClients.add(msg.replyTo);
                    break;
                case MSG_UNREGISTER_CLIENT:
                    Log.i("MyService", "Client un-registered: " + msg.replyTo);
                    mClients.remove(msg.replyTo);
                    break;
                default:
                    onReceiveMessage(msg);
            }
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        onStartService();
        Log.i("MyService", "Service Started.");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyService", "Received start id " + startId + ": " + intent);
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        onStopService();
        Log.i("MyService", "Service Stopped.");
    }
    protected void send(Message msg) {
        for (int i = mClients.size() - 1; i >= 0; i--) {
            try {
                Log.i("MyService", "Sending message to clients: " + msg);
                mClients.get(i).send(msg);
            } catch (RemoteException e) {
                Log.e("MyService", "Client is dead. Removing from list: " + i);
                mClients.remove(i);
            }
        }
    }
    public abstract void onStartService();
    public abstract void onStopService();
    public abstract void onReceiveMessage(Message msg);

}

AndroidManifest.xml

<service android:name=".MapAndService.Service15" />

If you have any question or suggestions kindly use the comment box or you can contact us directly through our contact page below.

Add a Comment