AIDL
Android Interface definition language 接口定义语言。不同的进程是不能通信的,通过aidl的方式来实现内存的共享,实现进程间的通信。
只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL,其他情况下你都可以选择其他方法,如使用Messager,也能跨进程通讯。可见AIDL是处理多线程、多客户端并发访问的。而Messager是单线程处理。
Stub
数据
AIDL只支持有限的数据类型:
1、java的简单类型(int double boolean),不需要导入
2、String和charsequence,不需要导入。
3、List和map,元素类型支持的是aidl支持的数据类型,不需要导入。
4、实现parcelable的类,需要导入。
内容
Android studio两个module即eclipse中的两个project
Module1:
首先定义AIDL接口:
package com.xhyy.lxr.testaidlapp; import com.xhyy.lxr.entity.Dog; // Declare any non-default types here with import statements interface MyAidl { String getName(); Dog getDog(); }
Android studio 中aidl生成:
在要生成aidl的包中 点击右键 生成AIDL File并命名,studio自动生成aidl文件夹和一致的包。声明两个方法 返回String和实体类。
package com.xhyy.lxr.entity; // Declare any non-default types here with import statements parcelable Dog;
Dog实体类类实现Parcelable接口 在Dog类的包点击右键,生成Dog的AIDL。肯定会重名,先随意写,再次rename即可。
结构如下
写完aidl之后,make project,这和普通的类不同,不会立即就能索引到。(还可以在gradle操作,待研究)
核心:MyService:
public class MyService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return binder; } MyAidl.Stub binder= new MyAidl.Stub() { @Override public String getName() throws RemoteException { return "我的刀快,是因为我直接。"; } @Override public Dog getDog() throws RemoteException { return new Dog("洪七"); } }; }
Manifest中注册,需要的是隐式intent绑定,故声明action。
<service android:name="com.xhyy.lxr.service.MyService"> <intent-filter> <action android:name="lxr.service.MyService"></action> </intent-filter> </service>
Module2
生成aidl。需要module1的aidl结构完全一致,先在java中建包(即使包是空的),再根据包生成aidl。内容和module1完全一致。
Aidl的内容复制粘贴就可以了。
两个module传递了dog实体类,因此module中也需要dog类来对接受到的数据进行规范。
核心操作:
public void doClick(View view){ Intent intent=new Intent("lxr.service.MyService"); Intent exIntent=getExplicitIntent(MainActivity.this,intent); bindService(exIntent,serviceConnection,BIND_AUTO_CREATE); }
public static Intent getExplicitIntent(Context context, Intent implicitIntent) { // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); List resolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) { return null; } // Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent; }
ServiceConnection serviceConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { myAidl=MyAidl.Stub.asInterface(service); try { String str=myAidl.getName(); Dog dog=myAidl.getDog(); mainTv.setText(dog.toString()+":"+str); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } };
关键代码:myAidl=MyAidl.Stub.asInterface(service);
得到module2 的MyAidl。
绑定的时候如果用的是intent 在Android 5.0以上就会崩溃。
解决方法,把intent变成显式的。(除此之外,还可以加上包名)
http://blog.csdn.net/vrix/article/details/45289207
注意action一定要谨慎,防止多写一个空格,连看都看不出来。
异常
包名不一致
java.lang.SecurityException: Binder invocation to an incorrect interface
Action加了空格
java.lang.IllegalStateException: Could not execute method of the activity空指针
5.0以上 隐式intent
Caused by: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent
魅族的开发者模式打开
*#*#6961#*#*
完毕。