AIDL 与 Messenger的异同
对于跨进程的调用
AIDL返回值是同步的,而Messenger是异步的。Aidl调用service的方法,会等待直到service中的方法执行完毕。
AIDL在Service中会针对每个请求开启新线程来执行客户端的调用。而Messenger会把消息放在主线程的队列里。
AIDL的实现,要注意线程安全的实现
oneway 关键字
修饰远程调用:
远程调用不会阻塞,它只是发送食物数据并立即返回
修饰本地进程:
不会有任何影响,调用仍是同步调用
AIDL支持的类型
- Java编程语言的原生基本类型 int、long、char、boolean
- String
- CharSequence
- List
- List中的所有元素必须是上面支持的类型
- 另一端实际接受的具体类型始终是ArrayList
- Map
- Map中所有的元素都必须是上面支持的类型
- 另一端实际接收的具体类始终是HashMap接口
必须为上面每个类加入import语句
一个AIDL的例子
Service端
1、编写AIDL的文件
// IAidlService.aidl package com.jue.testservice1; interface IAidlService { String getName(int num); }2、添加AndroidManifest文件
<service android:name=".AidlService" android:process=":AidlService" android:exported="true" android:enabled="true" > <intent-filter> <action android:name="com.jue.testservice1.IAidlService" /> </intent-filter> </service>
3、编写Servicepublic class AidlService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { logs("onBind thread-" + Thread.currentThread().getName()); return binder; } Binder binder = new IAidlService.Stub() { @Override public String getName(int num) throws RemoteException { logs("getName " + num + " start thread-" + Thread.currentThread().getName()); String data = "nothing"; try { Thread.sleep(1000); } catch (Exception e) { } if (num > 100) { data = " > 100, 百元"; } if (num > 0) { data = "0-100以内"; } logs("getName " + num + " end thread-" + Thread.currentThread().getName()); return data; } }; public static void logs(String text) { Log.i("jue","AidlService -> " + text); } }
Client端
4、添加一样的AIDL文件
package com.jue.testservice1; interface IAidlService { String getName(int num); }5、MainActivity的实现
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private int index; private IAidlService mIAidlService; private TextView mTitle; private View mBind; private View mUnbind; private View mGetData; private TextView mShowTitle; private View mShowBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTitle = (TextView)findViewById(R.id.title); mBind = findViewById(R.id.bind); mUnbind = findViewById(R.id.unbind); mGetData = findViewById(R.id.get_data); mShowTitle = (TextView) findViewById(R.id.show); mShowBtn = findViewById(R.id.show_btn); mBind.setOnClickListener(this); mUnbind.setOnClickListener(this); mGetData.setOnClickListener(this); mShowBtn.setOnClickListener(this); } @Override public void onClick(View v) { if (mBind == v) { Intent intent = new Intent(); intent.setAction("com.jue.testservice1.IAidlService"); intent.setPackage("com.jue.testservice1"); bindService(intent, connection, BIND_AUTO_CREATE); return; } if (mUnbind == v) { unbindService(connection); return; } if (mGetData == v) { String data = "default"; try { data = mIAidlService.getName(3002); } catch (RemoteException e) { e.printStackTrace(); } mTitle.setText(data); } if (mShowBtn == v) { mShowTitle.setText("" + index ++); return; } } private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { logs("onServiceConnected"); mIAidlService = IAidlService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { logs("onServiceDisconnected"); } }; public static void logs(String text) { Log.i("jue","MainActivity-> " + text); } }
.aidl文件编译之后
package com.jue.testservice1; public interface IAidlService extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.jue.testservice1.IAidlService { private static final java.lang.String DESCRIPTOR = "com.jue.testservice1.IAidlService"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.jue.testservice1.IAidlService interface, * generating a proxy if needed. */ public static com.jue.testservice1.IAidlService asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.jue.testservice1.IAidlService))) { return ((com.jue.testservice1.IAidlService) iin); } return new com.jue.testservice1.IAidlService.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_getName: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); java.lang.String _result = this.getName(_arg0); reply.writeNoException(); reply.writeString(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.jue.testservice1.IAidlService { 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 java.lang.String getName(int num) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(num); mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } public java.lang.String getName(int num) throws android.os.RemoteException; }
.aidl文件生成了同名的.java文件生成的同名.java文件,继承了 android.os.IInterface接口
package android.os; public interface IInterface { public IBinder asBinder(); }
Stub类
- 是一个抽象的内部类
- Stub实现了IAidlService接口
- Stub继承自android.os.Binder类 : 所以onBinder的时候,返回Stub对象就可以
- Stub类有一个方法是asInterface,参数是IBinder,返回值是IAidlService接口。:在ServiceConnected时,client可以创建IAidlService接口的对象
Aidl Service端的代码开启了新线程用来执行来自Client端的代码
AIDL的一些细节
- .aidl文件经过编译后会生成同名的.java文件。 如IRemoteService.aidl -> IRemoteService.java
- 使用aidl的方式,需要在一开始就做好多线程的处理准备。
- 如果明知服务完成请求的时间不止几毫秒,就不应该从Activity的主线程调用。通常需要从客户端的单独线程调用服务。
- Service端引发的任何异常都不会传递给调用方