Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 關於Android中的四大組件(AIDL Service的使用)

關於Android中的四大組件(AIDL 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服務,注意的是標簽中android:name的屬性值就是客戶端

 

要引用該服務的ID,也就是Intent類構造方法的參數值。

 

建立AIDL服務

 

以下程序是服務端創建了一個簡單的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();
	}

}

注意:以上的onBind()方法必須返回PersonImpl對象,否則客戶端無法獲得服務對象。

 

 

(4)在AndroidManifest.xml文件中配置MyService類,代碼如下:

 

 


            
                
            

注意:其中的“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() {
		
		@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服務傳遞一些復雜的數據需要做更一步處理,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;
		}
	}


}


 

先運行服務端程序,在運行客戶端程序,運行效果如下:

 

 

\

 

 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved