Android Service 之 AIDL
定義Service接口
Caution: AIDL 做的任何改變,都必須保持后向兼容
方法支持參數(shù)和返回值,參數(shù)和返回值可以是任意類型。
1. 所有Java原型都支持(int, long, float, char ,boolean等)
2. String
3. Charsequence
4. List,元素必須是支持的數(shù)據(jù)類型,也可是其他AIDL所申明的,或者是parcelables。同時也可使用泛型申明。實際使用ArrayList來存儲元素。
5. Map,也list要求相同。但不可使用泛型,實際使用HashMap來存儲。
如果要使用除以上數(shù)據(jù)的類型其他類型數(shù)據(jù),則必須使用import進行申明。
此外,在定義接口時,還需注意的有:
1. 方法可為0個或多個參數(shù),可返回值或者void
2. 所有非原型參數(shù),需要方向標簽,in,out,inout。
3. 所有代碼注釋都會被生成到j(luò)ava接口中,除了import和package申明之前的。
4. 只支持方法,不支持靜態(tài)成員變量的申明。
案例
// IRemoteService.aidl package com.example.android;// Declare any non-default types here with import statements/** Example service interface */ interface IRemoteService {/** Request the process ID of this service, to do evil things with it. */int getPid();/** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString); }Android SDK tools會根據(jù)aidl文件自動生成一個java語言的編程接口,這個接口包含一個繼承于Binder的抽象類和aidl中的接口方法實現(xiàn)。必須繼承Stub然后實現(xiàn)方法。
保存到/src目錄下,ADT tool 會在/gen目錄下生成IBinder接口文件。注意包名。
生成的接口包含一個子類Stub, 是對接口的抽象實現(xiàn)。因此,需要繼承該Stub,然后實現(xiàn)抽象方法。
其中Stub還有一個助手方法asInterface(),傳遞IBinder并返回stub接口實例。
實例代碼如下:
Caution: 注意多線程,要確保方法是線程安全的。RPC calls 通常是同步的,所以在client調(diào)用時,請使用子線程避免hand up the main thread and encounter ANR.此外,Server端不會返回Exception。
繼承Service,重寫onBind(),然后返回Stub 類的實現(xiàn),即mBinder。
Client調(diào)用,如果與Server不再同一個Application下,那么需要將aidl文件拷貝到Client,并且保持包名的一致。
Passing Objects over IPC
支持Parcelable,將允許Android系統(tǒng)decompose objects into primitives that can be marshalled over processes, 意思就是允許Android系統(tǒng)將objects 解耦成primitives,而這些primitives可在進程間傳遞。
Step:
1. 讓需要傳遞的類實現(xiàn)Parcelable接口,
2. 實現(xiàn)writeToParcel()方法,它將把對象的當前狀態(tài)寫到一個Parcel
3. 添加靜態(tài)字段CREATOR,它時實現(xiàn)Parcelable.Creator接口。
4. create a aidl, 然后申明這個Parcelable 類。
aidl 申明Rect類代碼如下:
package android.graphics;// Declare Rect so AIDL can find it and knows that it implements // the parcelable protocol. parcelable Rect;接下來是Rect類實現(xiàn)Parcelable接口代碼:
import android.os.Parcel; import android.os.Parcelable;public final class Rect implements Parcelable {public int left;public int top;public int right;public int bottom;public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {public Rect createFromParcel(Parcel in) {return new Rect(in);}public Rect[] newArray(int size) {return new Rect[size];}};public Rect() {}private Rect(Parcel in) {readFromParcel(in);}public void writeToParcel(Parcel out) {out.writeInt(left);out.writeInt(top);out.writeInt(right);out.writeInt(bottom);}public void readFromParcel(Parcel in) {left = in.readInt();top = in.readInt();right = in.readInt();bottom = in.readInt();} }Calling an IPC Method
調(diào)用遠程服務(wù)的實例,在之前的Service節(jié)中已經(jīng)出現(xiàn)過了。這里不妨再贅上,有效長,:)
public static class Binding extends Activity {/** The primary interface we will be calling on the service. */IRemoteService mService = null;/** Another interface we use on the service. */ISecondary mSecondaryService = null;Button mKillButton;TextView mCallbackText;private boolean mIsBound;/*** Standard initialization of this activity. Set up the UI, then wait* for the user to poke it before doing anything.*/@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.remote_service_binding);// Watch for button clicks.Button button = (Button)findViewById(R.id.bind);button.setOnClickListener(mBindListener);button = (Button)findViewById(R.id.unbind);button.setOnClickListener(mUnbindListener);mKillButton = (Button)findViewById(R.id.kill);mKillButton.setOnClickListener(mKillListener);mKillButton.setEnabled(false);mCallbackText = (TextView)findViewById(R.id.callback);mCallbackText.setText("Not attached.");}/*** Class for interacting with the main interface of the service.*/private ServiceConnection mConnection = new ServiceConnection() {public void onServiceConnected(ComponentName className,IBinder service) {// This is called when the connection with the service has been// established, giving us the service object we can use to// interact with the service. We are communicating with our// service through an IDL interface, so get a client-side// representation of that from the raw service object.mService = IRemoteService.Stub.asInterface(service);mKillButton.setEnabled(true);mCallbackText.setText("Attached.");// We want to monitor the service for as long as we are// connected to it.try {mService.registerCallback(mCallback);} catch (RemoteException e) {// In this case the service has crashed before we could even// do anything with it; we can count on soon being// disconnected (and then reconnected if it can be restarted)// so there is no need to do anything here.}// As part of the sample, tell the user what happened.Toast.makeText(Binding.this, R.string.remote_service_connected,Toast.LENGTH_SHORT).show();}public void onServiceDisconnected(ComponentName className) {// This is called when the connection with the service has been// unexpectedly disconnected -- that is, its process crashed.mService = null;mKillButton.setEnabled(false);mCallbackText.setText("Disconnected.");// As part of the sample, tell the user what happened.Toast.makeText(Binding.this, R.string.remote_service_disconnected,Toast.LENGTH_SHORT).show();}};/*** Class for interacting with the secondary interface of the service.*/private ServiceConnection mSecondaryConnection = new ServiceConnection() {public void onServiceConnected(ComponentName className,IBinder service) {// Connecting to a secondary interface is the same as any// other interface.mSecondaryService = ISecondary.Stub.asInterface(service);mKillButton.setEnabled(true);}public void onServiceDisconnected(ComponentName className) {mSecondaryService = null;mKillButton.setEnabled(false);}};private OnClickListener mBindListener = new OnClickListener() {public void onClick(View v) {// Establish a couple connections with the service, binding// by interface names. This allows other applications to be// installed that replace the remote service by implementing// the same interface.bindService(new Intent(IRemoteService.class.getName()),mConnection, Context.BIND_AUTO_CREATE);bindService(new Intent(ISecondary.class.getName()),mSecondaryConnection, Context.BIND_AUTO_CREATE);mIsBound = true;mCallbackText.setText("Binding.");}};private OnClickListener mUnbindListener = new OnClickListener() {public void onClick(View v) {if (mIsBound) {// If we have received the service, and hence registered with// it, then now is the time to unregister.if (mService != null) {try {mService.unregisterCallback(mCallback);} catch (RemoteException e) {// There is nothing special we need to do if the service// has crashed.}}// Detach our existing connection.unbindService(mConnection);unbindService(mSecondaryConnection);mKillButton.setEnabled(false);mIsBound = false;mCallbackText.setText("Unbinding.");}}};private OnClickListener mKillListener = new OnClickListener() {public void onClick(View v) {// To kill the process hosting our service, we need to know its// PID. Conveniently our service has a call that will return// to us that information.if (mSecondaryService != null) {try {int pid = mSecondaryService.getPid();// Note that, though this API allows us to request to// kill any process based on its PID, the kernel will// still impose standard restrictions on which PIDs you// are actually able to kill. Typically this means only// the process running your application and any additional// processes created by that app as shown here; packages// sharing a common UID will also be able to kill each// other's processes.Process.killProcess(pid);mCallbackText.setText("Killed service process.");} catch (RemoteException ex) {// Recover gracefully from the process hosting the// server dying.// Just for purposes of the sample, put up a notification.Toast.makeText(Binding.this,R.string.remote_call_failed,Toast.LENGTH_SHORT).show();}}}};// ----------------------------------------------------------------------// Code showing how to deal with callbacks.// ----------------------------------------------------------------------/*** This implementation is used to receive callbacks from the remote* service.*/private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {/*** This is called by the remote service regularly to tell us about* new values. Note that IPC calls are dispatched through a thread* pool running in each process, so the code executing here will* NOT be running in our main thread like most other things -- so,* to update the UI, we need to use a Handler to hop over there.*/public void valueChanged(int value) {mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));}};private static final int BUMP_MSG = 1;private Handler mHandler = new Handler() {@Override public void handleMessage(Message msg) {switch (msg.what) {case BUMP_MSG:mCallbackText.setText("Received from service: " + msg.arg1);break;default:super.handleMessage(msg);}}}; }總結(jié)
以上是生活随笔為你收集整理的Android Service 之 AIDL的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中西医与算法之间的联系
- 下一篇: nginx 正向代理配置