您的位置:首页 > 大数据 > 人工智能

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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android bindServic