AIDL随记(绑定本地和远程service)
2016-09-07 19:49
387 查看
本文讲述aidl的简单使用
首先我们来看绑定本地service的用法:
第一步:创建接口和实体类public interface IController { public User getUser(int index); }
public class User { private int age; private String name; public User(int age, String name) { super(); this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
第二步:创建本地service
public class MyService extends Service { public MyBinder mBinder = new MyBinder(); @Override public IBinder onBind(Intent intent) { return mBinder; } public class MyBinder extends Binder implements IController{ @Override public User getUser(int index) { // 这里返回查询的结果 return new User(20, "panpan"); } } }
第三步:绑定/解绑服务
public class TwoActivity extends Activity { private IController con; private MyConn conn; private TextView tv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_two); tv = (TextView) findViewById(R.id.tv); Intent service = new Intent(getApplicationContext(), MyService.class); conn = new MyConn(); bindService(service, conn, BIND_AUTO_CREATE); } public void two(View v){ User user = con.getUser(1); tv.setText(user.getName()+":"+user.getAge()+"岁"); } private class MyConn implements ServiceConnection{ @Override public void onServiceConnected(ComponentName name, IBinder service) { //绑定本地服务可以强制转换,绑定远程服务不可以,后面有讲 con = (IController) service; } @Override public void onServiceDisconnected(ComponentName name) { } } @Override protected void onDestroy() { super.onDestroy(); unbindService(conn);//一定不要忘记这一步 } }
最后不要忘记在AndroidManifest中注册service
以上代码很简单,不做解释
再来看看绑定远程服务的用法:
我们以两个Android工程来模拟客服端和服务端程序服务端代码:
创建一个接口:public interface IController { public User getUser(int index); }
创建一个实体类,实现Parcelable接口
public class User implements Parcelable { private int age; private String name; public User(int age, String name) { super(); this.age = age; this.name = name; } public User(Parcel in) { age = in.readInt(); name = in.readString(); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(age); dest.writeString(name); } public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() { public User createFromParcel(Parcel in) { return new User(in); } public User[] newArray(int size) { return new User[size]; } }; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
在Navigator视图中将接口IController.java后缀名.Java修改为.aidl(包视图修改不了)
修改好后切回包视图(Package Explorer),IController.aidl报错
根据提示把两个public删掉并为实体类User加上描述文件,在User类所在包右键->New->File,创建同名的.aidl文件,即:User.aidl
User.aidl的内容就两行
此时可以发现gen目录下自动产生了IController.aidl的Java语言解释类IController.java
内容如下
package com.ipjmc.scroller.contro; public interface IController extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.ipjmc.scroller.contro.IController { private static final java.lang.String DESCRIPTOR = "com.ipjmc.scroller.contro.IController"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.ipjmc.scroller.contro.IController interface, * generating a proxy if needed. */ public static com.ipjmc.scroller.contro.IController asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.ipjmc.scroller.contro.IController))) { return ((com.ipjmc.scroller.contro.IController)iin); } return new com.ipjmc.scroller.contro.IController.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_getUser: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); com.ipjmc.scroller.entity.User _result = this.getUser(_arg0); reply.writeNoException(); if ((_result!=null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.ipjmc.scroller.contro.IController { 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 com.ipjmc.scroller.entity.User getUser(int index) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); com.ipjmc.scroller.entity.User _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(index); mRemote.transact(Stub.TRANSACTION_getUser, _data, _reply, 0); _reply.readException(); if ((0!=_reply.readInt())) { _result = com.ipjmc.scroller.entity.User.CREATOR.createFromParcel(_reply); } else { _result = null; } } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_getUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } public com.ipjmc.scroller.entity.User getUser(int index) throws android.os.RemoteException; }
创建服务端service
public class MyService extends Service { public MyBinder mBinder = new MyBinder(); @Override public IBinder onBind(Intent intent) { return mBinder; } // 继承Stub就可以了,因为在IController.java中Stub就extends android.os.Binder 并且implements com.ipjmc.scroller.contro.IController,是不是觉得和绑定本地服务的时候有点像? public class MyBinder extends Stub{ @Override public User getUser(int index) { // 这里返回查询的结果 return new User(20, "panpan"); } } }
在AndroidManifest中注册service时添加过滤器intent-filter,因为跨进程访问service我们使用隐私意图
到此,服务端coding完成
再来看看客户端代码:
第一步:拷贝服务端以下内容到客户端src下(带包拷贝)
像这样
然后在Activity中绑定远程服务
public class MainActivity extends Activity { private TextView tv; private MyConn conn; private IController controller; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); Intent intent = new Intent("com.ipjmc.scroller.serveice.MyService"); conn = new MyConn(); bindService(intent, conn, BIND_AUTO_CREATE); } public class MyConn implements ServiceConnection{ @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub controller = Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } } @Override protected void onDestroy() { super.onDestroy(); unbindService(conn); } public void two(View v){ try { User user = controller.getUser(1); tv.setText(user.getName()+":"+user.getAge()+"岁"); } catch (RemoteException e) { e.printStackTrace(); } } }
客户端coding完成,但是需要注意的是,在Android5.0及以后,Android系统出于安全考虑,禁止隐士调用方式,程序运行报错:java.lang.IllegalArgumentException: Service Intent must be explicit,网上搜索到的解决方法:
//添加一个方法 public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) { // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); List<ResolveInfo> 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; }
Intent i = new Intent("com.ipjmc.scroller.serveice.MyService"); Intent intent = new Intent(createExplicitFromImplicitIntent(this,i)); conn = new MyConn(); bindService(intent, conn, BIND_AUTO_CREATE);
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories