In my previous post we discuss about the AIDL (IPC method
for Remote Service). But using AIDL method we can only pass primitive data type
(int ,float, boolean, char etc. ) and some predefined classes like String, CharSequence,
List, Map But when we want to pass the User defined class then AIDL unable
to pass these classes without make it Parcelable.
Note : Why we are use Parcelable interface ? Ans : In Android when we use AIDL for IPC then It use marshalling (Serialization) during sending the function argument,
and Unmarshalling during receiving the same argument. But when we want to send
and user defined object then it android unable to Marshall/Unmarshar , That why we need
Parcelable. We make the object as Parcelable. It is used to transmit the
message. It is a high-performance container for Android IPC.
The below example is modified of the my previous Post (AIDL). So I just give necessary extended code
used for Parcelable . You can get AIDL full code from here. In this example we pass a User defined class Student (data
member name, father_name ) from client to service using setName() . In service
side we capitalize the student name and again send Student object
using getName() and show in Toast.
Steps to Implement
the Parcelable over AIDL: Here I am giving some steps to implement the
Parcelable.
Step1 : Create a
different .aidl file that will be used
for define the Student class (Parcelable class).
(Student.aidl)
package com.aidl;
parcelable Student;
we write this because aidl can detect Student class.
Step 2: Define
the class as Parcelable by Implement the Parcelable.
(Student.java)
package com.aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class Student implements Parcelable {
public
String name;
public
String father_name;
public
Student(Parcel source)
{
name
= source.readString();
father_name
= source.readString();
}
public
Student()
{}
public
void setName(String name)
{
this.name
= name;
}
public
void setFatherName(String father_name)
{
this.father_name
= father_name;
}
@Override
public
int describeContents() {
//
TODO Auto-generated method stub
return
0;
}
@Override
public
void writeToParcel(Parcel dest, int flags) {
//
TODO Auto-generated method stub
dest.writeString(name);
dest.writeString(father_name);
}
public static final Parcelable.Creator<Student>
CREATOR = new Parcelable.Creator<Student>() {
@Override
public
Student createFromParcel(Parcel source) {
//
TODO Auto-generated method stub
return
new Student(source);
}
@Override
public
Student[] newArray(int size) {
//
TODO Auto-generated method stub
return
new Student[size];
}
};
}
Explanation:
Yellow Color code : Parcelable
interface has two abstract methods that we need to implement in class Student
- writeToParcel(Parcel dest, int flag) : This is the main method where we add data member to parcel using writeInt(), writeStirng () etc methods.
It has two methods –
1- T
createFromParcel(Parcel parcel) :This
method is called when UnMarshalling happen during receiving the data. Keep care that we receive the data member in same
sequence as we write in writeToPacel(). Here we create a constructor in which we demarshalling the
data.
2- NewArray(int
size) : Here we just create an array of given
size and return.
For set the data in
class I write setter methods setName() and setFatherName(). Its optional.
(Folder Structure) |
Note : Better to keep this Student.java
and Student.aidl in same package. And both should be copied in service side as
well as client side.
Step 3: In the
IRemoteInterface.aidl we change the argument type of methods
Student getName();
void setName(in
Student st);
When we are passing any User defined object in AIDL then we need
to specify in/out with argument
in – when the object is an IN Parameter
out – when the object is an OUT Parameter
Change should be in both side client as well as service.
Step 4: client side, we create the T (Student) type
object , set the name and father name. And send using setName(Student ) method.
@Override
public void
onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
Log.i("RemoteClient","In
onServicen binded...");
try
{
serviceInterface =
IRemoteInterface.Stub.asInterface(service);
Student
st1 = new Student();
st1.setName("Rahul");
st1.setFatherName("Nand
Kishor Kushwaha");
serviceInterface.setName(st1);
Log.i("RemoteClient","User
Name = "+serviceInterface.getName().name);
Toast.makeText(localContext, ""+serviceInterface.getName().name,
Toast.LENGTH_SHORT).show();
}
catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
Step 5: Client side, In the next line I am
getting the class Student from service using getName().
Log.i("RemoteClient","User
Name = "+serviceInterface.getName().name);
Step 6: : Service Side, Here
simply we receive the Student object in setName(). In getName() I alter the name
field of object and return it.
private IRemoteInterface.Stub
mBinder = new IRemoteInterface.Stub() {
@Override
public Student getName() throws RemoteException {
// TODO Auto-generated method
stub
stuInfo.name = stuInfo.name.toUpperCase();
return stuInfo;
}
@Override
public void setName(Student st) throws
RemoteException {
// TODO Auto-generated method
stub
stuInfo = st;
}
};
Thus we pass the user defined Object (Student object) from client to server and vice versa.
NOTE : AIDL also not able to send Date type object. In the next Post I will show How to send Date Type object.