Android AIDL 必看内容(转http://www.oschina.net/code/snippet_163910_6221)

Coordinator
May 11, 2012 at 3:38 AM
无鸯 发布于 2011年09月15日 9时, 0评/1118阅 <!-- #favor_form{width:200px;} #favor_form p {color:#666;} #favor_form form{height:60px;width:200px;} #favor_form form ._favor_input{display:block;margin:2px 0;width:199px;} #favor_form form ._favor_button{float:left;padding:2px 5px;} .favor_ok {text-align:center;font-size:10.5pt;width:199px;height:60px;margin-top:10px;} #TagsSwitcher{cursor:pointer;float:right;margin-top:10px;} #MyTags{display:none;width:199px;} #MyTags a.tag {float:left; background-color: #E0EAF1;border-bottom: 1px solid #3E6D8E;border-right: 1px solid #7F9FB6;color: #3E6D8E;font-size: 8pt;line-height: 16px;margin: 2px 2px 2px 0;padding: 2px 4px;text-decoration: none;white-space: nowrap;} --> 10人收藏此代码, 我要收藏
更好的设计Android软件应该熟悉掌握AIDL IPC机制,可以让你编写的组件类似Windows ActiveX COM一样更好的复用,提供类似像Symbian那样的服务器机制。服务可以很好的解决在后台运行无UI的窗口。我们创建一个aidl文件名为 android123.aidl下面是示例代码,修改于Android SDK文档。

代码片段(4)

[代码] 一、创建AIDL文件

view source
<object id="highlighter_446649_clipboard" title="copy to clipboard" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="16" height="16" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" type="application/x-shockwave-flash"> </object>
print?
01 ackage cn.com.android123;
02   
03 引入声明 
04 import cn.com.android123.IAtmService;
05   
06 // 声明一个接口,这里演示的是银行ATM程序
07 interface IBankAccountService {
08     int getAccountBalance(); //返回整数,无参数
09     void setOwnerNames(in List<String> names); //不返回,包含一个传入List参数
10     BankAccount createAccount(in String name, int startingDeposit, in IAtmService atmService); //返回一个自定义类型
11     int getCustomerList(in String branch, out String[] customerList); //返回整形,输入一个分支,输出一个客户列表
12 }

[代码] 二、实现一个接口

view source
<object id="highlighter_412906_clipboard" title="copy to clipboard" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="16" height="16" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" type="application/x-shockwave-flash"> </object>
print?
01 //显示的提供一个导出接口,为客户端提供绑定。
02   
03 public class RemoteService extends Service {
04     @Override
05     public IBinder onBind(Intent intent) {
06         if (IRemoteService.class.getName().equals(intent.getAction())) {
07             return mBinder;
08         }
09         if (ISecondary.class.getName().equals(intent.getAction())) {
10             return mSecondaryBinder;
11         }
12         return null;
13     }
14   
15  //第一个接口
16   
17     private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
18         public void registerCallback(IRemoteServiceCallback cb) {
19             if (cb != null) mCallbacks.register(cb);
20         }
21         public void unregisterCallback(IRemoteServiceCallback cb) {
22             if (cb != null) mCallbacks.unregister(cb);
23         }
24     };
25   
26 //第二个接口
27   
28     private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() {
29         public int getPid() {
30             return Process.myPid();
31         }
32         public void basicTypes(int anInt, long aLong, boolean aBoolean,
33                 float aFloat, double aDouble, String aString) {
34         }
35     };
36   
37 }

[代码] 三、客户端交互

view source
<object id="highlighter_231701_clipboard" title="copy to clipboard" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="16" height="16" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" type="application/x-shockwave-flash"> </object>
print?
01 /**
02 通过Android.os提供的Parcelable类型来传递数据,通常我们使用Eclipse+ADT插件来完成,在Eclipse中在Package Explorer view视图上单击鼠标右键,选择Create Aidl preprocess file for Parcelable classes(创建aidl预编译文件),最终我们创建一个名为android123.aidl文件
03 */
04   
05 import android.os.Parcel;
06 import android.os.Parcelable;
07   
08 public final class Rect implements Parcelable {
09 public int left;
10 public int top;
11 public int right;
12 public int bottom;
13   
14 public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {
15 public Rect createFromParcel(Parcel in) {
16 return new Rect(in);
17 }
18   
19 public Rect[] newArray(int size) {
20 return new Rect[size];
21 }
22 };
23   
24 public Rect() {
25 }
26   
27 private Rect(Parcel in) {
28 readFromParcel(in);
29 }
30   
31 public void writeToParcel(Parcel out) { //当前数据写入到Parcel中
32 out.writeInt(left);
33 out.writeInt(top);
34 out.writeInt(right);
35 out.writeInt(bottom);
36 }
37   
38 public void readFromParcel(Parcel in) { //从Parcel中读取数据
39 left = in.readInt();
40 top = in.readInt();
41 right = in.readInt();
42 bottom = in.readInt();
43 }
44 }

[代码] IPC调用方式

view source
<object id="highlighter_262242_clipboard" title="copy to clipboard" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="16" height="16" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" type="application/x-shockwave-flash"> </object>
print?
001 public class RemoteServiceBinding extends Activity {
002     /** The primary interface we will be calling on the service. */
003     IRemoteService mService = null;
004     /** Another interface we use on the service. */
005     ISecondary mSecondaryService = null;
006   
007     Button mKillButton;
008     TextView mCallbackText;
009   
010     private boolean mIsBound;
011   
012     /**
013      * Standard initialization of this activity.  Set up the UI, then wait
014      * for the user to poke it before doing anything.
015      */
016     @Override
017     protected void onCreate(Bundle savedInstanceState) {
018         super.onCreate(savedInstanceState);
019   
020         setContentView(R.layout.remote_service_binding);
021   
022         // Watch for button clicks.
023         Button button = (Button)findViewById(R.id.bind);
024         button.setOnClickListener(mBindListener);
025         button = (Button)findViewById(R.id.unbind);
026         button.setOnClickListener(mUnbindListener);
027         mKillButton = (Button)findViewById(R.id.kill);
028         mKillButton.setOnClickListener(mKillListener);
029         mKillButton.setEnabled(false);
030   
031         mCallbackText = (TextView)findViewById(R.id.callback);
032         mCallbackText.setText("Not attached.");
033     }
034   
035     /**
036      * Class for interacting with the main interface of the service.
037      */
038     private ServiceConnection mConnection = new ServiceConnection() {
039         public void onServiceConnected(ComponentName className,
040                 IBinder service) {
041             // This is called when the connection with the service has been
042             // established, giving us the service object we can use to
043             // interact with the service.  We are communicating with our
044             // service through an IDL interface, so get a client-side
045             // representation of that from the raw service object.
046             mService = IRemoteService.Stub.asInterface(service);
047             mKillButton.setEnabled(true);
048             mCallbackText.setText("Attached.");
049   
050             // We want to monitor the service for as long as we are
051             // connected to it.
052             try {
053                 mService.registerCallback(mCallback);
054             } catch (RemoteException e) {
055                 // In this case the service has crashed before we could even
056                 // do anything with it; we can count on soon being
057                 // disconnected (and then reconnected if it can be restarted)
058                 // so there is no need to do anything here.
059             }
060   
061             // As part of the sample, tell the user what happened.
062             Toast.makeText(RemoteServiceBinding.this, R.string.remote_service_connected,
063                     Toast.LENGTH_SHORT).show();
064         }
065   
066         public void onServiceDisconnected(ComponentName className) {
067             // This is called when the connection with the service has been
068             // unexpectedly disconnected -- that is, its process crashed.
069             mService = null;
070             mKillButton.setEnabled(false);
071             mCallbackText.setText("Disconnected.");
072   
073             // As part of the sample, tell the user what happened.
074             Toast.makeText(RemoteServiceBinding.this, R.string.remote_service_disconnected,
075                     Toast.LENGTH_SHORT).show();
076         }
077     };
078   
079     /**
080      * Class for interacting with the secondary interface of the service.
081      */
082     private ServiceConnection mSecondaryConnection = new ServiceConnection() {
083         public void onServiceConnected(ComponentName className,
084                 IBinder service) {
085             // Connecting to a secondary interface is the same as any
086             // other interface.
087             mSecondaryService = ISecondary.Stub.asInterface(service);
088             mKillButton.setEnabled(true);
089         }
090   
091         public void onServiceDisconnected(ComponentName className) {
092             mSecondaryService = null;
093             mKillButton.setEnabled(false);
094         }
095     };
096   
097     private OnClickListener mBindListener = new OnClickListener() {
098         public void onClick(View v) {
099             // Establish a couple connections with the service, binding
100             // by interface names.  This allows other applications to be
101             // installed that replace the remote service by implementing
102             // the same interface.
103             bindService(new Intent(IRemoteService.class.getName()),
104                     mConnection, Context.BIND_AUTO_CREATE);
105             bindService(new Intent(ISecondary.class.getName()),
106                     mSecondaryConnection, Context.BIND_AUTO_CREATE);
107             mIsBound = true;
108             mCallbackText.setText("Binding.");
109         }
110     };
111   
112     private OnClickListener mUnbindListener = new OnClickListener() {
113         public void onClick(View v) {
114             if (mIsBound) {
115                 // If we have received the service, and hence registered with
116                 // it, then now is the time to unregister.
117                 if (mService != null) {
118                     try {
119                         mService.unregisterCallback(mCallback);
120                     } catch (RemoteException e) {
121                         // There is nothing special we need to do if the service
122                         // has crashed.
123                     }
124                 }
125   
126                 // Detach our existing connection.
127                 unbindService(mConnection);
128                 unbindService(mSecondaryConnection);
129                 mKillButton.setEnabled(false);
130                 mIsBound = false;
131                 mCallbackText.setText("Unbinding.");
132             }
133         }
134     };
135   
136     private OnClickListener mKillListener = new OnClickListener() {
137         public void onClick(View v) {
138             // To kill the process hosting our service, we need to know its
139             // PID.  Conveniently our service has a call that will return
140             // to us that information.
141             if (mSecondaryService != null) {
142                 try {
143                     int pid = mSecondaryService.getPid();
144                     // Note that, though this API allows us to request to
145                     // kill any process based on its PID, the kernel will
146                     // still impose standard restrictions on which PIDs you
147                     // are actually able to kill.  Typically this means only
148                     // the process running your application and any additional
149                     // processes created by that app as shown here; packages
150                     // sharing a common UID will also be able to kill each
151                     // other's processes.
152                     Process.killProcess(pid);
153                     mCallbackText.setText("Killed service process.");
154                 } catch (RemoteException ex) {
155                     // Recover gracefully from the process hosting the
156                     // server dying.
157                     // Just for purposes of the sample, put up a notification.
158                     Toast.makeText(RemoteServiceBinding.this,
159                             R.string.remote_call_failed,
160                             Toast.LENGTH_SHORT).show();
161                 }
162             }
163         }
164     };
165   
166     // ----------------------------------------------------------------------
167     // Code showing how to deal with callbacks.
168     // ----------------------------------------------------------------------
169   
170     /**
171      * This implementation is used to receive callbacks from the remote
172      * service.
173      */
174     private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
175         /**
176          * This is called by the remote service regularly to tell us about
177          * new values.  Note that IPC calls are dispatched through a thread
178          * pool running in each process, so the code executing here will
179          * NOT be running in our main thread like most other things -- so,
180          * to update the UI, we need to use a Handler to hop over there.
181          */
182         public void valueChanged(int value) {
183             mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));
184         }
185     };
186   
187     private static final int BUMP_MSG = 1;
188   
189     private Handler mHandler = new Handler() {
190         @Override public void handleMessage(Message msg) {
191             switch (msg.what) {
192                 case BUMP_MSG:
193                     mCallbackText.setText("Received from service: " + msg.arg1);
194                     break;
195                 default:
196                     super.handleMessage(msg);
197             }
198         }
199   
200     };