Developing Android Remote Services PRO

The first step is coding the aidl file that includes our definition for the interface that lists the methods we want to enable their invocation from another process.

package com.abelski.currencyservice;

interface ICurrencyService
{
  double getCurrency(String country);
}

The aidl compiler will go over that file and auto generate the interface we defined in the aidl file. Within that interface the aidl compiler will define Stub.

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /Users/haimmichael/Desktop/android_remote_service/currency_service/src/com/abelski/currencyservice/ICurrencyService.aidl
 */
package com.abelski.currencyservice;
public interface ICurrencyService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.abelski.currencyservice.ICurrencyService
{
private static final java.lang.String DESCRIPTOR = "com.abelski.currencyservice.ICurrencyService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.abelski.currencyservice.ICurrencyService interface,
 * generating a proxy if needed.
 */
public static com.abelski.currencyservice.ICurrencyService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.abelski.currencyservice.ICurrencyService))) {
return ((com.abelski.currencyservice.ICurrencyService)iin);
}
return new com.abelski.currencyservice.ICurrencyService.Stub.Proxy(obj);
}
public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getCurrency:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
double _result = this.getCurrency(_arg0);
reply.writeNoException();
reply.writeDouble(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.abelski.currencyservice.ICurrencyService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
public double getCurrency(java.lang.String country) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
double _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(country);
mRemote.transact(Stub.TRANSACTION_getCurrency, _data, _reply, 0);
_reply.readException();
_result = _reply.readDouble();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getCurrency = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public double getCurrency(java.lang.String country) throws android.os.RemoteException;
}

The next step is defining a class that extends Service. This class should include the definition for the onBind method that should return a reference for a new object instantiated from a class that extends Stub and implements the abstract methods.

package com.abelski.currencyservice;

import android.os.RemoteException;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class CurrencyService extends Service
{
	public class CurrencyServiceImpl extends ICurrencyService.Stub
	{
		@Override
		public double getCurrency(String ticker) throws RemoteException
		{
			return 3.86;
		}
	}

	@Override
	public void onCreate()
	{
		super.onCreate();
	}

	@Override
	public void onDestroy()
	{
		super.onDestroy();
	}

	@Override
	public void onStart(Intent intent, int startId)
	{
		super.onStart(intent, startId);
	}

	@Override
	public IBinder onBind(Intent intent)
	{
		return new CurrencyServiceImpl();
	}
}

When coding the client we should use the very same aidl interface that we were using on the server. In addition we should define a class that implements ServiceConnection. That class includes the definition for call back functions that will be invoked when binding and when unbinding. When binding the call back function that will be invoked will take care of calling the Stub.asInterface method in order to get an object that serves as kind of a representative for the real object on the server side.

package com.abelski.currencyclient;

import com.abelski.currencyservice.ICurrencyService;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.ComponentName;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import android.app.Activity;

public class MainActivity extends Activity {
	private ICurrencyService currencyService = null;
	private Button bindBt;
	private Button callBt;
	private Button unbindBt;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		bindBt = (Button) findViewById(R.id.bind);
		bindBt.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View view) {
				if (bindService(new Intent(ICurrencyService.class.getName()),
						serviceConnection, Context.BIND_AUTO_CREATE)) {
					bindBt.setEnabled(false);
					callBt.setEnabled(true);
					unbindBt.setEnabled(true);
					Toast.makeText(MainActivity.this,
							"Currency Remote Service is Binded",
							Toast.LENGTH_SHORT).show();
				} else {
					Toast.makeText(MainActivity.this,
							"Currency Remote Service can not be Binded",
							Toast.LENGTH_SHORT).show();
				}
			}
		});
		callBt = (Button) findViewById(R.id.call);
		callBt.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View view) {
				callService();
			}
		});
		unbindBt = (Button) findViewById(R.id.unbind);
		unbindBt.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View view) {
				unbindService(serviceConnection);
				bindBt.setEnabled(true);
				callBt.setEnabled(false);
				unbindBt.setEnabled(false);
				Toast.makeText(MainActivity.this,
						"Currency Remote Service is not Binded", Toast.LENGTH_SHORT)
						.show();
			}
		});
		unbindBt.setEnabled(false);
		callBt.setEnabled(false);
	}

	private void callService() {
		try {
			double result = currencyService.getCurrency("USD");
			Toast.makeText(MainActivity.this,
					"Currency Exchange Rate of USD is " + result,
					Toast.LENGTH_SHORT).show();
		} catch (RemoteException exception) {
		}
	}

	private ServiceConnection serviceConnection = new ServiceConnection() {
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			currencyService = ICurrencyService.Stub.asInterface(service);
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			currencyService = null;
		}
	};
}

The following video clip overviews this code sample, shows its execution and explains it. You can download the code sample and goes over it together with the video clip.

Share:

The Visitor Design Pattern

The Visitor Design Pattern

The visitor design pattern allows us to add operations to objects that already exist without modifying their classes and without extending them.

What are Anti Patterns?

Anti Patterns

Unlike design patterns, anti patterns just seem to be a solution. However, they are not a solution and they cause additional costs.

Virtual Threads in Java Professional Seminar

Virtual Threads in Java

The use of virtual threads can assist us with improving the performance of our code. Learn how to use virtual threads effectively.

NoSQL Databases Courses, Seminars, Consulting, and Development

MongoDB Design Patterns Meetup

The use of MongoDB involves with various cases in which we can overcome performance issues by implementing specific design patterns.

image of woman and database

Record Classes in Java

Learn how to define record classes in Java, and when to use record classes in your code. Stay up to date with the new Java features.

Accessibility | Career | Conferences | Design Patterns | JavaScript | Meetups | PHP | Podcasts | Python | Self Learning

Teaching Methodologies | Fullstack | C++ | C# | CSS | Node.js | Angular | Java | Go | Android | Kotlin | Swift | Academy

Front End Development | Scala | Architectures | Cloud | Big Data | Internet of Things | Kids Learn Programming

The Beauty of Code

Coding is Art! Developing Code That Works is Simple. Develop Code with Style is a Challenge!

Skip to content Update cookies preferences