編輯:關於Android編程
Android系統中的進程之間不能共享內存,因此,需要提供一些機制在不同進程之間進行數據通信。
在前一篇文章(關於Android中的四大組件(Service的開啟與關閉))中介紹了開發人員如何定制自己的服務,但這些
服務並不能被其它的應用程序訪問,為了使其它的應用程序也可以訪問本應用程序提供的服務,Android系統采用了
遠程過程調用(Remote Procedure Call,RPC)方式來實現。與很多其它的基於RPC的解決方案一樣,Android使用一種
接口定義語言(Interface Definition Language,IDL)來公開服務的接口,因此,可以將這種跨進程訪問的服務稱為
(Android Interface Definition Language)AIDL服務。
建立AIDL服務比普通的服務要復雜一些,具體步驟如下。
(1)在Eclipse Android工程的Java源文件目錄中建立一個擴展名為aidl的文件,該文件的語法類似於Java代
碼,但會稍不同。
(2)如果aidl文件的內容是正確的,ADT會自動生成一個Java接口文件(*.java)。
(3)建立一個服務類(Service的子類)。
(4)實現由aidl文件生成的Java接口。
(5)在AndroidManifest.xml文件中配置AIDL服務,注意的是標簽中android:name的屬性值就是客戶端
要引用該服務的ID,也就是Intent類構造方法的參數值。
以下程序是服務端創建了一個簡單的AIDL服務,這個服務有兩個get方法,分別獲取姓名和年齡,創建此AIDL服務的步驟
如下。
(1)建立一個aidl文件,如下圖中的IPerson.aidl文件。

IPerson.aidl文件的內容如下:
package com.aidl; interface IPerson{ String getName(); int getAge(); }
IPerson.aidl文件的內容與Java代碼非常相似,但要注意,不能加修飾符,比如:public、private,同時AIDL服
務不支持的數據類型例如:InputStream、OutputStream等內容。
(2)如果IPerson.adil文件中內容正確,ADT會自動生成一個IPerson.java文件。
(3)編寫一個MyService類,該類繼承自Service,在MyService類中定義了一個內聯類PersonImpl,該類繼承自
IPerson.Stub,MyService類的代碼如下:
public class MyService extends Service{
public class PersonImpl extends IPerson.Stub{
@Override
public String getName() throws RemoteException {
return bill;
}
@Override
public int getAge() throws RemoteException {
return 25;
}
}
@Override
public IBinder onBind(Intent intent) {
return new PersonImpl();
}
}
(4)在AndroidManifest.xml文件中配置MyService類,代碼如下:
至此服務端的AIDL服務編寫完成,接下來進行客戶端代碼的編寫,新建工程,將服務端的自動生成的
IPerson.java文件連同包目錄一起復制到客戶端工程中,如下圖:

以下程序實現了綁定AIDL服務,以及獲取服務端數據:
public class MainActivity extends Activity implements OnClickListener{
private Button btn_aidl;
private Button btn_get;
private TextView tv_show;
private Intent mIpItent;
private IPerson mIpIPerson=null;
private ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIpIPerson=IPerson.Stub.asInterface(service);
btn_get.setEnabled(true);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
initEvent();
}
private void initData(){
mIpItent=new Intent(com.aidl.IPerson);
}
private void initView(){
btn_aidl=(Button) this.findViewById(R.id.btn_aidl);
btn_get=(Button) this.findViewById(R.id.btn_get);
tv_show=(TextView) this.findViewById(R.id.tv_show);
btn_get.setEnabled(false);
}
private void initEvent(){
btn_aidl.setOnClickListener(this);
btn_get.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_aidl://綁定AIDL服務
bindService(mIpItent, conn, Context.BIND_AUTO_CREATE);
break;
case R.id.btn_get://獲取服務端數據
try {
tv_show.setText(姓名:+mIpIPerson.getName()+
年齡:+mIpIPerson.getAge());
} catch (RemoteException e) {
e.printStackTrace();
}
default:
break;
}
}
}
以上代碼使用bindService方法來綁定AIDL服務,其中需要指定AIDL服務的ID,也就是標簽中的
android:name屬性值。在綁定時需要一個ServiceConnection對象,當綁定成功,系統調用
ServiceConnection.onServiceConnected方法,通過此方法的service參數獲取AIDL服務對象。最後先運行服務端程
序,再運行客戶端程序。
效果如下:

AIDL服務只支持有限的數據類型,因此,如果用AIDL服務傳遞一些復雜的數據需要做更一步處理,AIDL服務支
持的數據類型如下。
(1)java的簡單類型(int、char、boolean等),不需要導入。
(2)String和CharSequence,不需要導入。
(3)List和Map,List和Map對象的元素類型必須是AIDL服務支持的數據類型,不需要導入。
(4)AIDL自動生成的接口,需要導入。
(5)實現android.os.Parcelable接口的類,需要導入。
以下程序傳遞的數據類型是Person類,服務端代碼如下:
(1)新建Person實現Parcelable接口
public class Person implements Parcelable{
private String name;
private int age;
public static final Parcelable.Creator CREATOR=new Creator() {
@Override
public Person[] newArray(int size) {
return new Person[size];
}
@Override
public Person createFromParcel(Parcel source) {
return new Person(source.readInt(),source.readString());
}
};
public Person(){
}
public Person(int age,String name){
this.name=name;
this.age=age;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Person實現android.os.Parcelable這個接口,該接口用於序列化對象,在Person類中必須有一個靜態常量,常量
名必須是CREATOR,而且CREATOR常量的數據類型必須是Parcelable.Creator。在writeToParcel方法中需要將序列
化的值寫入Parcel對象,注意,讀取的順序必須和寫入的順序保持一致。
(2)接著建立一個IPerson.aidl文件,代碼如下:
package com.aidl;
import com.aidl.Person;
interface IPerson{
Person getPerson();
}
(3)建立一個Person.aidl文件,代碼如下:
package com.aidl; parcelable Person;
(4)創建一個MyService類,代碼如下:
public class MyService extends Service {
public class PersonImpl extends IPerson.Stub {
@Override
public Person getPerson() throws RemoteException {
Person person = new Person();
person.setName(bill);
person.setAge(25);
return person;
}
}
@Override
public IBinder onBind(Intent intent) {
return new PersonImpl();
}
}
最後服務端的工程目錄結構如下圖:

OK,服務端的AIDL服務編寫完畢,接著編寫客戶端程序,將服務端的Person.java與IPerson.aidl連同包一起復
制到客戶端工程中,如下圖:

以下代碼實現了獲取服務端的Person對象中的數據:
public class MainActivity extends Activity implements OnClickListener{
private Button btn_aidl;
private Button btn_get;
private TextView tv_show;
private Intent mIpItent;
private IPerson mIpIPerson=null;
private ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIpIPerson=IPerson.Stub.asInterface(service);
btn_get.setEnabled(true);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
initEvent();
}
private void initData(){
mIpItent=new Intent(com.bill.aidl.IPerson);
}
private void initView(){
btn_aidl=(Button) this.findViewById(R.id.btn_aidl);
btn_get=(Button) this.findViewById(R.id.btn_get);
tv_show=(TextView) this.findViewById(R.id.tv_show);
btn_get.setEnabled(false);
}
private void initEvent(){
btn_aidl.setOnClickListener(this);
btn_get.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_aidl://綁定AIDL服務
bindService(mIpItent, conn, Context.BIND_AUTO_CREATE);
break;
case R.id.btn_get://獲取服務端數據
try {
Person person=mIpIPerson.getPerson();
tv_show.setText(姓名:+person.getName()+
年齡:+person.getAge());
} catch (RemoteException e) {
e.printStackTrace();
}
default:
break;
}
}
}
先運行服務端程序,在運行客戶端程序,運行效果如下:

Android開發之Drag&Drop框架實現拖放手勢
Android3.0提供了drag/drop框架,利用此框架可以實現使用拖放手勢將一個view拖放到當前布局中的另外一個view中。本文將介紹如何使用拖放框架。 一、實
實例詳解Android Selector和Shape的用法
shape和selector是Android UI設計中經常用到的,比如我們要自定義一個圓角Button,點擊Button有些效果的變化,就要用到shape和select
Android 工廠模式,三種工廠模式的理解
工廠模式是一種創建者模式,在任何生成復雜對象的地方都可以使用工廠模式。理論來說在任何使用A a = new A()的方式都可以使用工廠模式,雖然使用工廠模式可能需要多做一
android搶紅包代碼解析支持微信與QQ
最近有一段時間沒寫博客了,一方面是工作比較忙,一方面也著實本人水平有限,沒有太多能與大家分享的東西,也就是在最近公司要做一個搶紅包的功能,老板發話了咋們就開干呗,本人就開