带着这三个问题去学习AIDL,我想思路就会很明朗。
package com.beyole.aidl;
interface ICaculate{
int add(int a,int b);
}
这里我们公布给客户端的只有一个add方法,由于我用的是eclipse编辑器,所以会在gen目录下自动编译生成ICaculate.java:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\Java\\Android4\\beyoleaidlserver\\src\\com\\beyole\\aidl\\ICaculate.aidl
*/
package com.beyole.aidl;
public interface ICaculate extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.beyole.aidl.ICaculate
{
private static final java.lang.String DESCRIPTOR = "com.beyole.aidl.ICaculate";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.beyole.aidl.ICaculate interface,
* generating a proxy if needed.
*/
public static com.beyole.aidl.ICaculate asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.beyole.aidl.ICaculate))) {
return ((com.beyole.aidl.ICaculate)iin);
}
return new com.beyole.aidl.ICaculate.Stub.Proxy(obj);
}
@Override 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_add:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.beyole.aidl.ICaculate
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public int add(int a, int b) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public int add(int a, int b) throws android.os.RemoteException;
}
因为这里是初学如何使用aidl,所以我们不会在此处多解释,具体的在下篇深入aidl博客中介绍。其实,这里的抽象静态Stub类就是我们要返回给客户端的IBinder代理对象。
package com.beyole.service;
import com.beyole.aidl.ICaculate;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class CaculateService extends Service {
private ICaculate.Stub myBinder = new MyIBinder();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
}
继承Service,主要的在onBind中返回代理对象。有人不禁要问,这里的代理对象是什么,上面也提到过,就是我们aidl文件的静态抽象Stub实现类,我们也把我们的ICaculate.Stub代码也提供一下吧。
package com.beyole.service;
import android.os.RemoteException;
import com.beyole.aidl.*;
public class MyIBinder extends ICaculate.Stub {
@Override
public int add(int a, int b) throws RemoteException {
return (a + b);
}
}
这里的add方法就是公布给客户端使用方法的具体处理,如果你要和service进行绑定的话,其实你可以在MyIBinder的构造方法中传入service,然后在service中进行逻辑的处理,那样也是可以的。写好了service,当然也要在我们的AndroidManifest文件中注册我们的service。在AndroidManifest.xml中添加:
这里我想说个小插曲,其实我们的android基本项目中不一定要有Activity的,我们这里就是只有一个service也是可以的。好,服务端到此结束,开始客户端。
我们想要的效果就是在前两个edittext中输入数字,然后点击计算,在第三个edittext中显示结果。可能有人要说,要这么麻烦干嘛,直接在一个工程中搞定就好了,为什么还要多进程呢?我们这边演示的例子并不能很好的体现aidl的优势,其实想QQ类似的聊天软件,都是采用多进程的,一个主进程,一个负责消息收发的处理进程,用户登录处理不在主进程中处理,那么用户名密码等操作都是通过aidl来的。
package com.example.beyoleaidltest;
import android.app.Activity;
import android.app.Service;
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.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.beyole.aidl.ICaculate;
public class MainActivity extends Activity {
private ICaculate caculate;
private Button btn;
private EditText editText, editText2, editText3;
private MyServiceConnection connection = new MyServiceConnection();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.id_btn);
editText = (EditText) findViewById(R.id.id_edt);
editText2 = (EditText) findViewById(R.id.id_edt1);
editText3 = (EditText) findViewById(R.id.id_edt2);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
editText.setText(caculate.add(Integer.parseInt(editText2.getText().toString()), Integer.parseInt(editText3.getText().toString())) + "");
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(MainActivity.this, "Service Connected!", Toast.LENGTH_SHORT).show();
caculate = ICaculate.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(MainActivity.this, "Service Disconnected!", Toast.LENGTH_SHORT).show();
caculate = null;
}
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent();
intent.setAction("com.beyole.service.calc");
bindService(intent, connection, Service.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
}
进程之间通信都是通过ServiceConnection来完成的,它有两个方法:
public void onServiceConnected(ComponentName name, IBinder service)
public void onServiceDisconnected(ComponentName name)
顾名思义,一个是service连接时的处理,一个是没有连接时的处理。我们在onServiceConnected中获取代理对象,在onServiceDisconnected中进行对象置空。
caculate = ICaculate.Stub.asInterface(service);
这是最关键的一步,就是拿到我们的代理对象,剩下的所有操作都是通过这个对象进行远程调用的。
Intent intent = new Intent();
intent.setAction("com.beyole.service.calc");
bindService(intent, connection, Service.BIND_AUTO_CREATE);
然后在onDestroy中进行解绑。
unbindService(connection);
一切就绪,拿到的代理对象直接在button的点击事件中使用:
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
editText.setText(caculate.add(Integer.parseInt(editText2.getText().toString()), Integer.parseInt(editText3.getText().toString())) + "");
} catch (Exception e) {
e.printStackTrace();
}
}
});
题外话:
android交流群:279031247(广告勿入)
新浪微博:SmartIceberg