Friday, 2 October 2015

AIDL in android example


AIDL (Android Interface Definition Language)


Every Android application runs in its own process. So one application cannot access another application's memory 

So to let this happen we need to decompose their objects into primitives that the operating system can understand and marshall the objects across that boundary for you.

 The code to do that marshalling is tedious to write, so Android handles it for you with AIDL - meaning, Inter Process communication (IPC) can be handled easily through AIDL. 

This as a communication between client and server applications. Client sends a request and server responds back.



AIDL can be achieved following the below steps :
Define AIDL Interface - AIDL that Interfaces your applications. 
Implement the Interface -  The above interface will be implemented in the service so that clients can access.
Expose the Interface to clients- To expose the interface for your service, extend Service and implement onBind()

Here I am explaining AIDL with simple for adding two number.For this we need two applications,this is client and server. Client application get the input from user via UI and send the request to the server application.Service application receive the I request and process and send the response to the client application.

Server application:
Define AIDL Interface
                 This file defines programming interface with method signature.
 AIDL interface should be defined in filename .aidl
IAdd.aidl


package com.example.android_additionservice;
 interface IAdd
 {
   int add(int num1, int num2);  }

When we build our application, Android SDK generates .java file corresponding to this .aidl file with the same name like IAdd.java. The generated interface includes a subclass named Stub that is an abstract implementation of its parent interface and declares all the methods from the .aidl file

Implement the Interface:
To implement the interface generated from the .aidl, extend the generated Binder interface and implement the methods inherited from the .aidl file. On our case we need to implement the add method here. Now the mBinder is an instance of the Stub class (a Binder), which defines the RPC interface for the service.
After implementing the interface, we need to expose it to other applications to access it. For which extend service and implement onBind() to return an instance of your class that implements the generated stub.


public class AdditionService extends Service {
 public IBinder onBind(Intent intent) {
  // TODO Auto-generated method stub
  return mBinder;
 }
  /**
  * IAdd definition is below
  */
 private final IAdd.Stub mBinder = new IAdd.Stub() {
  @Override
  public int add(int num1, int num2) throws RemoteException {
   // TODO Auto-generated method stub
   return (num1 + num2);
  }
 };
}



Client Application:
Create UI:
Create UI to get the input from the user.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/sum"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <EditText
        android:id="@+id/value1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <EditText
        android:id="@+id/value2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:weightSum="3" >
        <Button
            android:id="@+id/add"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Add" />
    </LinearLayout>
</LinearLayout> 

Include the same Iadd.aidl file

Register the service in the AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.aidl"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
          <service
            android:name=".AdditionService"
            android:process=":remote" >
            <intent-filter>
                <action android:name="service.Calculator" />
            </intent-filter>
        </service>
    </application>
</manifest>

Client logic:
Here we need the estabilish the connection between the client and server application.
For this create a new inner class by implementing ServiceConnection.

Also we need to implement onServiceConnected() and onServiceDiconnected()  methods in this class.These methods are the callbacks, which will get the stub implementation of the remote service on connection.

In your implementation of onServiceConnected(), you will receive an IBinder instance (called service). Call IAdd.Stub.asInterface((IBinder)service) to cast the returned parameter to our interface type. Then bind to the service

MainActivityClient.java


public class MainActivityClient extends Activity implements OnClickListener {
EditText etValue1, etValue2;
Button bAdd;
TextView mSum;
protected IAdd AddService;
ServiceConnection AddServiceConnection;

 /** Called when the activity is first created. */

 @Override
public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 etValue1 = (EditText) findViewById(R.id.value1);
 etValue2 = (EditText) findViewById(R.id.value2);
 mSum = (TextView) findViewById(R.id.sum);
 bAdd = (Button) findViewById(R.id.add);
 bAdd.setOnClickListener(this);
 initConnection();
}

 void initConnection() {
 AddServiceConnection = new ServiceConnection() {

   @Override
  public void onServiceDisconnected(ComponentName name) {
   // TODO Auto-generated method stub
   AddService = null;
   Toast.makeText(getApplicationContext(), "Service Disconnected",
     Toast.LENGTH_SHORT).show();
   Log.d("IRemote", "Binding - Service disconnected");
  }

   @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   // TODO Auto-generated method stub
   AddService = IAdd.Stub.asInterface((IBinder) service);
   Toast.makeText(getApplicationContext(),
     "Addition Service Connected", Toast.LENGTH_SHORT)
     .show();
   Log.d("IRemote", "Binding is done - Service connected");
  }
 };
 if (AddService == null) {
  Intent it = new Intent();
  it.setAction("service.Calculator");
  // binding to remote service
  bindService(it, AddServiceConnection, Service.BIND_AUTO_CREATE);
 }
}

 protected void onDestroy() {
 super.onDestroy();
 unbindService(AddServiceConnection);
};

 public void onClick(View v) {
 // TODO Auto-generated method stub
 switch (v.getId()) {
 case R.id.add: {
  int num1 = Integer.parseInt(etValue1.getText().toString());
  int num2 = Integer.parseInt(etValue2.getText().toString());
  try {
  int result = AddService.add(num1, num2);
   mSum.setText("Result:" + AddService.add(num1, num2));
   Log.d("IRemote", "Binding - Add operation");
  } catch (RemoteException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
  break;
 }
}
}



Run the application:
First run the server application.It will show the default app message,
Then, run the client application and enter the inputs in the field and you can get the addition value as result.




DOWNLOAD SOURCE CODE

No comments: