yueguc 发表于 2013-1-15 02:26:19

Android AIDL必看内容

更好的设计Android软件应该熟悉掌握AIDL IPC机制,可以让你编写的组件类似Windows ActiveX COM一样更好的复用,提供类似像Symbian那样的服务器机制。服务可以很好的解决在后台运行无UI的窗口。我们创建一个aidl文件名为 android123.aidl下面是示例代码,修改于Android SDK文档。

一、创建AIDL文件

package cn.com.android123;

引入声明 import cn.com.android123.IAtmService;

// 声明一个接口,这里演示的是银行ATM程序
interface IBankAccountService {
   
    int getAccountBalance(); //返回整数,无参数
    void setOwnerNames(in List<String> names); //不返回,包含一个传入List参数
    BankAccount createAccount(in String name, int startingDeposit, in IAtmService atmService); //返回一个自定义类型
    int getCustomerList(in String branch, out String[] customerList); //返回整形,输入一个分支,输出一个客户列表
}

二、实现一个接口

显示的提供一个导出接口,为客户端提供绑定。

public class RemoteService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
      if (IRemoteService.class.getName().equals(intent.getAction())) {
            return mBinder;
      }
      if (ISecondary.class.getName().equals(intent.getAction())) {
            return mSecondaryBinder;
      }
      return null;
    }

//第一个接口

    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
      public void registerCallback(IRemoteServiceCallback cb) {
            if (cb != null) mCallbacks.register(cb);
      }
      public void unregisterCallback(IRemoteServiceCallback cb) {
            if (cb != null) mCallbacks.unregister(cb);
      }
    };

//第二个接口

    private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() {
      public int getPid() {
            return Process.myPid();
      }
      public void basicTypes(int anInt, long aLong, boolean aBoolean,
                float aFloat, double aDouble, String aString) {
      }
    };

}

三、客户端交互

通过Android.os提供的Parcelable类型来传递数据,通常我们使用Eclipse+ADT插件来完成,在Eclipse中在 Package Explorer view视图上单击鼠标右键,选择Create Aidl preprocess file for Parcelable classes(创建aidl预编译文件),最终我们创建一个名为android123.aidl文件

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;
      }
    };

    public Rect() {
    }

    private Rect(Parcel in) {
      readFromParcel(in);
    }

    public void writeToParcel(Parcel out) { //当前数据写入到Parcel 中
      out.writeInt(left);
      out.writeInt(top);
      out.writeInt(right);
      out.writeInt(bottom);
    }

    public void readFromParcel(Parcel in) { //从Parcel 中读取数据
      left = in.readInt();
      top = in.readInt();
      right = in.readInt();
      bottom = in.readInt();
    }
}

IPC调用方式

public class RemoteServiceBinding 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.
   */
    @Override
    protected 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(RemoteServiceBinding.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(RemoteServiceBinding.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(RemoteServiceBinding.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);
            }
      }

    };
}
页: [1]
查看完整版本: Android AIDL必看内容