標籤:parcelable aidl service service android 四大組件
跨進程調用Service(AIDL Service)
Android系統中的進程之間不能共用記憶體,因此,需要提供一些機制在不同進程之間進行資料通訊。
在前一篇文章(關於Android中的四大組件(Service的開啟與關閉))中介紹了開發人員如何定製自己的服務,但這些
服務並不能被其它的應用程式訪問,為了使其它的應用程式也可以訪問本應用程式提供的服務,Android系統採用了
遠端程序呼叫(Remote Procedure Call,RPC)方式來實現。與很多其它的基於RPC的解決方案一樣,Android使用一種
介面定義語言(Interface Definition Language,IDL)來公開服務的介面,因此,可以將這種跨進程訪問的服務稱為
(Android Interface Definition Language)AIDL服務。
AIDL服務的建立步驟
建立AIDL服務比普通的服務要複雜一些,具體步驟如下。
(1)在Eclipse Android工程的Java源檔案目錄中建立一個副檔名為aidl的檔案,該檔案的文法類似於Java代
碼,但會稍不同。
(2)如果aidl檔案的內容是正確的,ADT會自動產生一個Java介面檔案(*.java)。
(3)建立一個服務類(Service的子類)。
(4)實現由aidl檔案產生的Java介面。
(5)在AndroidManifest.xml檔案中配置AIDL服務,注意的是<action>標籤中android:name的屬性值就是用戶端
要引用該服務的ID,也就是Intent類構造方法的參數值。
建立AIDL服務
以下程式是服務端建立了一個簡單的AIDL服務,這個服務有兩個get方法,分別擷取姓名和年齡,建立此AIDL服務的步驟
如下。
(1)建立一個aidl檔案,如中的IPerson.aidl檔案。
IPerson.aidl檔案的內容如下:
<pre name="code" class="html">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{@Overridepublic String getName() throws RemoteException {return "bill";}@Overridepublic int getAge() throws RemoteException {return 25;}}@Overridepublic IBinder onBind(Intent intent) {return new PersonImpl();}}
注意:以上的onBind()方法必須返回PersonImpl對象,否則用戶端無法獲得服務物件。
(4)在AndroidManifest.xml檔案中配置MyService類,代碼如下:
<service android:name="com.example.aidlserviceproject.service.MyService"> <intent-filter > <action android:name="com.aidl.IPerson"/> </intent-filter></service>
注意:其中的“com.aidl.IPerson”是用戶端用於訪問AIDL服務的ID。
至此服務端的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() {@Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic 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); } @Overridepublic 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()+"\n年齡:"+mIpIPerson.getAge());} catch (RemoteException e) {e.printStackTrace();}default:break;}}}
以上代碼使用bindService方法來綁定AIDL服務,其中需要指定AIDL服務的ID,也就是<action>標籤中的
android:name屬性值。在綁定時需要一個ServiceConnection對象,當綁定成功,系統調用
ServiceConnection.onServiceConnected方法,通過此方法的service參數擷取AIDL服務物件。最後先運行服務端程
序,再運行用戶端程式。
效果如下:
傳遞複雜資料的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<Person> CREATOR=new Creator<Person>() {@Overridepublic Person[] newArray(int size) {return new Person[size];}@Overridepublic 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;}@Overridepublic int describeContents() {return 0;}@Overridepublic 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 {@Overridepublic Person getPerson() throws RemoteException {Person person = new Person();person.setName("bill");person.setAge(25);return person;}}@Overridepublic 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() {@Overridepublic void onServiceDisconnected(ComponentName name) {}@Overridepublic 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); } @Overridepublic 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()+"\n年齡:"+person.getAge());} catch (RemoteException e) {e.printStackTrace();}default:break;}}}
先運行服務端程式,在運行用戶端程式,運行效果如下:
-------------------------------------------------------------------------------------------------------------------------------------------------------
轉載請註明出處:http://blog.csdn.net/hai_qing_xu_kong/article/details/47748779情緒控
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
關於Android中的四大組件(AIDL Service的使用)