在Android平台中,一个进程通常不能访问其他进程中的内存区域的。但是,我们可以使用IDL语言来把对象伪装成操作系统能理解的简单形式,以便伪装成对象跨越边界访问。
如果想在应用程序中调用其他进程中的Service,则需要用到AIDL,AIDL(android接口描述语言)是一种IDL语言,它可以生成一段代码,可以使在一个android设备上运行的两个进程使用内部通信进程进行交互。如果你需要在一个进程中(例如:在一个Activity中)访问另一个进程中(例如:一个Service)某个对象的方法,你就可以使用AIDL来生成这样的代码来伪装传递各种参数。
使用AIDL的方法如下:
1.首先要编写一个 IMusicService.aidl的服务接口,ADT会根据这个接口文件帮我们自动生成一个 Stub类,这个类继承了Binder类,同时继承了IMusicService这个接口,还可以看到其中包含了一个Proxy代理类,以实现远程代理,访问不同的进程。(aidl和Stub类如下所示)。
- /**
- * IMusicService.aidl
- * com.androidtest.service.mediaplayer
- *
- * Function: TODO
- *
- * ver date author
- * ──────────────────────────────────
- * 2011-5-19 Leon
- *
- * Copyright (c) 2011, TNT All Rights Reserved.
- */
- package com.zuiniuwang.service;
- /**
- * ClassName:IMusicService
- * Function: TODO ADD FUNCTION
- * Reason: TODO ADD REASON
- *
- * @author Leon
- * @version
- * @since Ver 1.1
- * @Date 2011-5-19
- */
- interface IMusicService{
- void play();
- void pause();
- void stop();
- }
2. 生成的Stub类如下,我们暂不做详细讲解,后面的课程中我们会尝试自己来写一个类似的类,完成不同进程的访问。
- /*
- * This file is auto-generated. DO NOT MODIFY.
- * Original file: E:\\myworkspace\\musicservice4\\src\\com\\zuiniuwang\\service\\IMusicService.aidl
- */
- package com.zuiniuwang.service;
- /**
- * ClassName:IMusicService
- * Function: TODO ADD FUNCTION
- * Reason: TODO ADD REASON
- *
- * @author Leon
- * @version
- * @since Ver 1.1
- * @Date 2011-5-19
- */
- public interface IMusicService extends android.os.IInterface
- {
- /** Local-side IPC implementation stub class. */
- public static abstract class Stub extends android.os.Binder implements com.zuiniuwang.service.IMusicService
- {
- private static final java.lang.String DESCRIPTOR = "com.zuiniuwang.service.IMusicService";
- /** Construct the stub at attach it to the interface. */
- public Stub()
- {
- this.attachInterface(this, DESCRIPTOR);
- }
- /**
- * Cast an IBinder object into an com.zuiniuwang.service.IMusicService interface,
- * generating a proxy if needed.
- */
- public static com.zuiniuwang.service.IMusicService asInterface(android.os.IBinder obj)
- {
- if ((obj==null)) {
- return null;
- }
- android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
- if (((iin!=null)&&(iin instanceof com.zuiniuwang.service.IMusicService))) {
- return ((com.zuiniuwang.service.IMusicService)iin);
- }
- return new com.zuiniuwang.service.IMusicService.Stub.Proxy(obj);
- }
- public android.os.IBinder asBinder()
- {
- return this;
- }
- @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
- {
- switch (code)
- {
- case INTERFACE_TRANSACTION:
- {
- reply.writeString(DESCRIPTOR);
- return true;
- }
- case TRANSACTION_play:
- {
- data.enforceInterface(DESCRIPTOR);
- this.play();
- reply.writeNoException();
- return true;
- }
- case TRANSACTION_pause:
- {
- data.enforceInterface(DESCRIPTOR);
- this.pause();
- reply.writeNoException();
- return true;
- }
- case TRANSACTION_stop:
- {
- data.enforceInterface(DESCRIPTOR);
- this.stop();
- reply.writeNoException();
- return true;
- }
- }
- return super.onTransact(code, data, reply, flags);
- }
- private static class Proxy implements com.zuiniuwang.service.IMusicService
- {
- private android.os.IBinder mRemote;
- Proxy(android.os.IBinder remote)
- {
- mRemote = remote;
- }
- public android.os.IBinder asBinder()
- {
- return mRemote;
- }
- public java.lang.String getInterfaceDescriptor()
- {
- return DESCRIPTOR;
- }
- public void play() throws android.os.RemoteException
- {
- android.os.Parcel _data = android.os.Parcel.obtain();
- android.os.Parcel _reply = android.os.Parcel.obtain();
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_play, _data, _reply, 0);
- _reply.readException();
- }
- finally {
- _reply.recycle();
- _data.recycle();
- }
- }
- public void pause() throws android.os.RemoteException
- {
- android.os.Parcel _data = android.os.Parcel.obtain();
- android.os.Parcel _reply = android.os.Parcel.obtain();
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_pause, _data, _reply, 0);
- _reply.readException();
- }
- finally {
- _reply.recycle();
- _data.recycle();
- }
- }
- public void stop() throws android.os.RemoteException
- {
- android.os.Parcel _data = android.os.Parcel.obtain();
- android.os.Parcel _reply = android.os.Parcel.obtain();
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0);
- _reply.readException();
- }
- finally {
- _reply.recycle();
- _data.recycle();
- }
- }
- }
- static final int TRANSACTION_play = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
- static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
- static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
- }
- public void play() throws android.os.RemoteException;
- public void pause() throws android.os.RemoteException;
- public void stop() throws android.os.RemoteException;
- }
3. 在Activity中得到Binder的方式,是通过Stub类的IMusicService.Stub.asInterface(binder)方法(这一点和以前不同)。相应的代码如下:
- /**
- * RemoteMusicPlayerActivity.java
- * com.androidtest.activity.musicplayer
- *
- * Function: TODO
- *
- * ver date author
- * ──────────────────────────────────
- * 2011-5-20 Leon
- *
- * Copyright (c) 2011, TNT All Rights Reserved.
- */
- package com.zuiniuwang.playeractivity;
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Context;
- import android.content.Intent;
- import android.content.ServiceConnection;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import com.zuiniuwang.R;
- import com.zuiniuwang.service.IMusicService;
- /**
- * ClassName:RemoteMusicPlayerActivity Function: TODO ADD FUNCTION Reason: TODO
- * ADD REASON
- *
- * @author Leon
- * @version
- * @since Ver 1.1
- * @Date 2011-5-20
- */
- public class RemoteMusicPlayerActivity extends Activity implements
- OnClickListener {
- private static final String TAG = RemoteMusicPlayerActivity.class
- .getSimpleName();
- private Button playButton, pauseButton, stopButton, closeActivityButton,
- exitActivityButton;
- private IMusicService musicServiceInterface;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- this.setContentView(R.layout.music_player_layout);
- findViews();
- bindViews();
- connection();
- }
- private void findViews() {
- playButton = (Button) this.findViewById(R.id.play);
- pauseButton = (Button) this.findViewById(R.id.pause);
- stopButton = (Button) this.findViewById(R.id.stop);
- closeActivityButton = (Button) this.findViewById(R.id.close);
- exitActivityButton = (Button) this.findViewById(R.id.exit);
- }
- private void bindViews() {
- playButton.setOnClickListener(this);
- pauseButton.setOnClickListener(this);
- stopButton.setOnClickListener(this);
- closeActivityButton.setOnClickListener(this);
- exitActivityButton.setOnClickListener(this);
- }
- private void connection() {
- Intent intent = new Intent(
- "com.androidtest.service.mediaplayer.RemoteMusicService");
- this.startService(intent);
- this.bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE);
- }
- private ServiceConnection myServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- musicServiceInterface = IMusicService.Stub.asInterface(binder);
- Log.d(TAG, " onServiceConnected");
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- musicServiceInterface = null;
- Log.d(TAG, " onServiceDisconnected");
- }
- };
- @Override
- public void onClick(View view) {
- // TODO Auto-generated method stub
- try {
- switch (view.getId()) {
- case R.id.play:
- Log.d(TAG, "play.......");
- musicServiceInterface.play();
- break;
- case R.id.pause:
- Log.d(TAG, "pause.......");
- musicServiceInterface.pause();
- break;
- case R.id.stop:
- Log.d(TAG, "stop.......");
- musicServiceInterface.stop();
- break;
- case R.id.close:
- //Activity退出之前要解除绑定,不然会报错
- this.unbindService(myServiceConnection);
- Log.d(TAG, "close.......");
- this.finish();
- break;
- case R.id.exit:
- Log.d(TAG, "exit.......");
- this.unbindService(myServiceConnection);
- this.stopService(new Intent("com.androidtest.service.mediaplayer.RemoteMusicService"));
- this.finish();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
4. 最后在此Service注册的时候我们需要指定它是在一个不同的进程中运行的,本例子指定的是remote进程。注意 process参数。
- <!-- 注册Service -->
- <service android:enabled="true"
- android:name=".service.RemoteMusicService" android:process=":remote">
- <intent-filter>
- <action android:name="com.androidtest.service.mediaplayer.RemoteMusicService" />
- </intent-filter>
- </service>
本节的源代码可在此下载:http://down.51cto.com/data/326382