AIDL 服務只支持有限的數據類型,如果用AIDL服務傳遞一些複雜的數據就需要做更一步處理, AIDL 服務支持的數據類型如下:
1. Java 的基本數據類型(不需要import)
2. String 和CharSequence(不需要import)
3. List 和 Map ,List和Map 對象的元素必須是AIDL支持的數據類型; (以上三種類型都不需要import)
4. AIDL 自動生成的接口 (需要import)
5. 實現android.os.Parcelable 接口的類. (需要import)
要傳遞一個需要import 的數據類型的值(如: 實現Parcelable接口的類),除了要建立一個實現Parcelable 接口的類外, 還需要爲這個類單獨建立一個aidl 文件, 並使用parcelable 關鍵字進行定義。
########################################
下面編寫一個可以傳遞Product對象的AIDL服務。
步驟1,新建類Product.java,實現Parcelable接口。代碼如下:
package com.example.service07_aidlservice; import android.os.Parcel; import android.os.Parcelable; public class Product implements Parcelable { private int id; private String name; private float price; public Product() { } public Product(Parcel in) { id = in.readInt(); name = in.readString(); price = in.readFloat(); } /* * 在Product 類中必須有一個靜態常量,常量名必須爲CREATOR,而且CREATOR 常量的數據類型必須是Parcelable.Creator */ public static final Parcelable.Creator<Product> CREATOR = new Parcelable.Creator<Product>() { @Override public Product createFromParcel(Parcel in) { return new Product(in); } @Override public Product[] newArray(int size) { return new Product[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeString(name); dest.writeFloat(price); } //getter 和 setter 省略 }
步驟2 ,爲這個類單獨建立一個aidl 文件, 並使用parcelable 關鍵字進行定義,Product.aidl代碼如下
parcelable Product; // parcelable 首字母是小寫
步驟3,新建IMyService.aidl文件,代碼如下:
package com.example.service07_aidlservice; import com.example.service07_aidlservice.Product;//必須導包 import java.util.Map;//可以不導包 interface IMyService { //由於product只用於輸入,因此需要加in 修飾符 Map getMap(in String country,in Product product); Product getProduct(); }
步驟4,編寫一個Seravice類,MyService.java代碼如下:
package com.example.service07_service; import java.util.HashMap; import java.util.Map; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import com.example.service07_aidlservice.IMyService.Stub; import com.example.service07_aidlservice.Product; public class MyService extends Service { private MyBinder myBinder; @Override public IBinder onBind(Intent intent) { return new MyBinder(); } /* * 該類繼承了IMyService.Stub類而不是extends Binder類。 * IMyService.Stub是Binder的子類。 * 進程內的Service定義MyBinder內部類是繼承Binder類。 */ private class MyBinder extends IMyService.Stub { @Override public Map getMap(String country, Product product) throws RemoteException { Map map = new HashMap<String, String>(); map.put("country", country); map.put("id", product.getId()); map.put("name", product.getName()); map.put("price", product.getPrice()); map.put("product", product); return map; } @Override public Product getProduct() throws RemoteException { Product product = new Product(); product.setId(1234); product.setName("奔馳"); product.setPrice(300000); return product; } } }
步驟5,在AndroidManifest.xml中註冊Service,並去掉MianActivity的配置。
<service android:name="com.example.service07_service.MyService" > <intent-filter> <!-- 指定客戶端調用AIDL服務所需要的Action --> <action android:name="com.example.service07.aidl" /> </intent-filter> </service>
服務端的代碼結構如下:
步驟6,客戶端的編寫:新建客戶端項目,把IMyService.aidl,Product.aidl,Product.java 連同包一起拷貝到Client的src目錄。注意,實體類也要拷貝過去。這幾個類最好放在一個包下,因爲我放在不同的包下一直報錯找不到類,即使我正確的導包了還是報錯。
步驟7,編寫MainActivity.java 和 xml佈局文件;界面提供了2個按鈕。BIND 按鈕 和 INVOKE 按鈕.
package com.example.service07_aidlclient; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import com.example.service07_aidlservice.IMyService; import com.example.service07_aidlservice.Product; public class MainActivity extends Activity implements OnClickListener { Button btnBind;//點擊該按鈕,啓動遠程Service Button btnInvoke;//點擊該按鈕,遠程調用Service IMyService mBinder; // 接口的一個引用 private ServiceConnection mConn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { /* * 獲得另一個進程中的Service傳遞過來的對象service, * 用IMyService.Stub.asInterface方法轉換該對象,這點與進程內的通信不同 */ mBinder = IMyService.Stub.asInterface(service); btnInvoke.setEnabled(true); Log.i("MainActivity", "onServiceConnected...."); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnBind = (Button) findViewById(R.id.btn_bind); btnInvoke = (Button) findViewById(R.id.btn_invoke); btnBind.setOnClickListener(this); btnInvoke.setOnClickListener(this); } @Override public void onClick(View v) { Intent intent = new Intent(); int btn = v.getId(); switch (btn) { case R.id.btn_bind: //Constant類中定義了要遠程調用的服務 //public static final String ACTION_SERVICE = "com.example.service07.aidl"; intent.setAction(Constant.ACTION_SERVICE); bindService(intent, mConn, BIND_AUTO_CREATE); break; case R.id.btn_invoke: try { Product p = mBinder.getProduct(); Log.i("TAG", mBinder.getMap("country", p).toString()); Log.i("TAG", p.getName()); } catch (RemoteException e) { e.printStackTrace(); } break; } } }
步驟8,先運行service服務端,再運行client客服端,得到結果如下: