AIDL简介
AIDL即Android接口描述语言,用于跨进程之间的数据通信。关于其详细的信息可以网上搜,相关内容还是蛮多的。
基本类型的AIDL
AIDL支持的6中基本类型
byte,double,float,int,long,String
现在我们来实现AIDL的方法吧
1.实现*.aidl文件
IAIDLTest.aidl
package com.pachongzhang.myservice;
interface IAIDLTest {
int add(int a, int b);
}
aidl文件的生成与一个接口类(interface)类的实现差不多,首先声明其所在的包名,然后定义其接口类,只是少了public,private这些属性,并且其支持的类型比较少。那我们要实现自定义类用于参数传递,我们就需要让自定义类实现Parcelable接口。下面我们来看下自定义类的AIDL的实现。
自定义类的AIDL
自定义类实现Parcelable,我们需要创建两个文件,.java和.aidl,下面举一个具体的实例。
CustomParcelable.java
package com.pachongzhang.myservice;
import android.os.Parcel;
import android.os.Parcelable;
public class CustomParcelable implements Parcelable {
private int a;
private String b;
public CustomParcelable(Parcel source) {
this.a = source.readInt();
this.b = source.readString();
}
public CustomParcelable(int a, String b) {
this.a = a;
this.b = b;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(a);
dest.writeString(b);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
public CustomParcelable createFromParcel(Parcel source) {
return new CustomParcelable(source);
}
@Override
public CustomParcelable[] newArray(int size) {
return new CustomParcelable[size];
}
};
}
CustomParcelable.aidl
package com.pachongzhang.myservice;
parcelable CustomParcelable;
从CustomParcelable.java可知其主要用于自定义类的实现方法,CustomParcelable.aidl用于其在AIDL的声明,那么我们要怎么样才能使用这个自定义类呢。
IAIDLTest.aidl
package com.pachongzhang.myservice;
import com.pachongzhang.myservice.CustomParcelable;
interface IAIDLTest {
int add(int a, int b);
void getCustom(in CustomParcelable custom);
}
从代码中我们可以看到IAIDLTest.aidl文件多了import com.pachongzhang.myservice.CustomParcelable;一个这样的声明,这个就是我们自己定义的那个类,有了这个声明我们就可以在.aidl文件中使用CustomParcelable这个类了,同时要注意的两点就是我们定义了CustomParcelable.java文件还是声明其CustomParcelable.aidl文件,其次是做为参数传递时要声明其是in还是out的方式表示其是输入参数还是输出参数。
说了这么多,我们看下具体的使用吧
AIDL的实践
Service端
首先,我们看service端的实现
代码结构
从Myservice的结构中,我们已经实现了CustomParcelable.java,CustomParcelable.aidl和IAIDLTest.aidl,下面我就看下MyService.java和AndroidManifest.xml。
MyService.java
package com.pachongzhang.myservice;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class MyService extends Service{
protected static final String TAG = "MyService";
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private Binder mBinder = new IAIDLTest.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
return (a+b);
}
@Override
public void getCustom(CustomParcelable custom) throws RemoteException {
Log.d(TAG,"getCustom:"+custom.getA()+",getB:"+custom.getB());
}
};
@Override
public void onDestroy() {
mBinder = null;
}
}
从MyService.java中我们可以看到我们实现了IAIDLTest.Stub()类,这个类就是用于接口数据传递及其实现,可以看到我们实现了add和getCustom方法。然后通过onBind把IAIDLTest.Stub()对象传递给别的进程,已使其调用MyService 里的方法。我们定义了服务自然而然就要在AndroidManifest.xml中声明。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pachongzhang.myservice"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<service android:name="com.pachongzhang.myservice.MyService" >
<intent-filter>
<action android:name="com.pachongzhang.myservice.MyService.start" />
</intent-filter>
</service>
</application>
</manifest>
可以看到我们声明了MyService服务,并定义了一个action=”com.pachongzhang.myservice.MyService.start”方便别的进程启动本服务。下面来看下Client端访问本服务的方法。
Client端
Client端的代码结构
从结构中我们知道,我们要把那些接口类都搬过来,如果使用了自定义类,还要把自定义的类的java和aidl文件搬过来。所以这么我们就只需要看下MainActivity.java和activity_main.xml的实现了。先来看下Client端实现的效果吧。
这里我们通过调用Service的add方法实现了加法运算。并且通过getCustom打印了对应的信息
效果看过后我们看MainActivity.java和activity_main.xml的实现吧。
activity_main.xml
<LinearLayout 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"
android:orientation="vertical" >
<EditText
android:id="@+id/id_edit_num1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="+" />
<EditText
android:id="@+id/id_edit_num2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number" />
<Button
android:id="@+id/id_btn_equal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="=" />
<EditText
android:id="@+id/id_edit_num3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false" />
</LinearLayout>
MainActivity.java
package com.pachongzhang.myclient;
import com.pachongzhang.myservice.CustomParcelable;
import com.pachongzhang.myservice.IAIDLTest;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity implements OnClickListener {
private static final String SERVICE_START = "com.pachongzhang.myservice.MyService.start";
private EditText mEditNum1;
private EditText mEditNum2;
private EditText mEditNum3;
private Button mBtnEqual;
private IAIDLTest mService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
bindService(true);
}
@Override
protected void onDestroy() {
bindService(false);
super.onDestroy();
}
private void bindService(boolean isBind){
if (isBind) {
Intent intent = new Intent(SERVICE_START);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
} else {
if (mServiceConnection != null) {
unbindService(mServiceConnection);
mServiceConnection = null;
}
}
}
private void initView() {
mEditNum1 = (EditText) findViewById(R.id.id_edit_num1);
mEditNum2 = (EditText) findViewById(R.id.id_edit_num2);
mEditNum3 = (EditText) findViewById(R.id.id_edit_num3);
mBtnEqual = (Button) findViewById(R.id.id_btn_equal);
mBtnEqual.setOnClickListener(this);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IAIDLTest.Stub.asInterface(service);
}
};
@Override
public void onClick(View v) {
if (v.getId() == R.id.id_btn_equal) {
int num1 = Integer.valueOf(mEditNum1.getText().toString());
int num2 = Integer.valueOf(mEditNum2.getText().toString());
try {
int num3 = mService.add(num1, num2);
mEditNum3.setText(num3+"");
CustomParcelable customParcelable = new CustomParcelable(num3, "Success");
mService.getCustom(customParcelable);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
MainActivity.java的实现也是比较简单的,就简单介绍下,通过bindService获得远程服务的binder,然后通过它就可以调用那些接口了。
Android自定义类序列化
Android序列化一般是用于对象的传递的,因为在Android中一些自定义类对象是不能直接传递的,需要序列化。那我们来看看有哪些序列化的方式,Serializable是java提供的,Parcelable是Android提供的,相对来说Serializable的实现要简单很多,但Parcelable的效率要比Serializable高,可以参考这篇文章Android系统中Parcelable和Serializable的区别。下面我们来看下Parcelable和Serializable的简单实现。
Parcelable
MyParcelable.java
import android.os.Parcel;
import android.os.Parcelable;
public class MyParcelable implements Parcelable{
private int a;
private String b;
public MyParcelable(Parcel source) {
this.a = source.readInt();
this.b = source.readString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(a);
dest.writeString(b);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
public MyParcelable createFromParcel(Parcel source) {
return new MyParcelable(source);
}
@Override
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
}
Serializable
MySerializable.java
import java.io.Serializable;
public class MySerializable implements Serializable {
private static final long serialVersionUID = 6285493298229159093L;
private int a;
private String b;
}
从上面两个简单类里我们可以看出Parcelable要比Serializable 复杂的多,但是效率上正好相反。所以在使用上还是推荐使用Parcelable。