// Iservice.aidl
package com.leehour.aidldemo;
// Declare any non-default types here with import statements
interface Iservice {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
boolean callPay(String name, String pwd, int money);
}
public static abstract class Stub extends android.os.Binder implements com.leehour.aidldemo.Iservice
意味着我们在服务里面可以用到Stub类,这里先提一下,后面看具体用法。
pay()
package com.leehour.aidldemo;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
public class PaySerivce extends Service {
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public boolean pay(String name, String pwd, int money) {
System.out.println("name:"+name+"pwd:"+pwd+"money:"+money);
if ("abc".equals(name) && "123".equals(pwd) && money < 5000) {
return true;
} else {
return false;
}
}
private class MyBinder extends Iservice.Stub {
@Override
public boolean callPay(String name, String pwd, int money) throws RemoteException {
return pay(name,pwd,money);
}
}
}
此时我们使用到了Stub类,这样我们可以通过新建的MyBinder类继承Stub来创建MyBinder对象,在onBind方法中返回一个MyBinder对象。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="买豆"
android:onClick="click"/>
LinearLayout>
// Iservice.aidl
package com.leehour.aidldemo;
// Declare any non-default types here with import statements
interface Iservice {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
boolean callPay(String name, String pwd, int money);
}
在mainActivity中加入如下代码:
package com.leehour.happydoudizhu;
import android.app.Activity;
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.util.Log;
import android.view.View;
import android.widget.Toast;
import com.leehour.aidldemo.Iservice;
/**
* Created by leehour on 2016/9/9.
*/
public class MainActivity extends Activity {
private MyConn conn;
private Iservice iservice;
private Intent intentService=new Intent();
final String BOUNDSERVICE_PACKAGE = "com.leehour.aidldemo";
final String BOUNDSERVICE_CLASS = ".PaySerivce";
//Bound Service Connection
/*private ServiceConnection conn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder boundService) {
iservice = Iservice.Stub.asInterface(boundService);
}
public void onServiceDisconnected(ComponentName name) {
}
};*/
private class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
iservice = Iservice.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentService.setClassName(BOUNDSERVICE_PACKAGE,
BOUNDSERVICE_PACKAGE + BOUNDSERVICE_CLASS);
conn=new MyConn();
bindService(intentService, conn, BIND_AUTO_CREATE);
}
public void click(View view) {
try {
boolean result = iservice.callPay("abc", "123", 100);
if (result) {
Toast.makeText(getApplicationContext(), "买豆成功", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "买豆失败", Toast.LENGTH_LONG).show();
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
其中BOUNDSERVICE_PACKAGE
和BOUNDSERVICE_CLASS
是第一个app的包名和服务的类名,这里我们使用的是MyConn
直接实现的ServiceConnection
接口,也可以使用上面注释里面的方法。
这样就做好了两个app,将第一个部署到模拟机上,再部署第二个,点击“买豆”按钮,就会弹出吐司“买豆成功”,大功告成!
首先,来看一下生成的整个Iservice.java
文件,代码如下:
public interface Iservice extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.example.developmentarts.Iservice {
private static final java.lang.String DESCRIPTOR = "com.example.developmentarts.Iservice";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.developmentarts.Iservice interface,
* generating a proxy if needed.
*/
public static com.example.developmentarts.Iservice asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.developmentarts.Iservice))) {
return ((com.example.developmentarts.Iservice) iin);
}
return new com.example.developmentarts.Iservice.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_callPay: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _arg1;
_arg1 = data.readString();
int _arg2;
_arg2 = data.readInt();
boolean _result = this.callPay(_arg0, _arg1, _arg2);
reply.writeNoException();
reply.writeInt(((_result) ? (1) : (0)));
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.developmentarts.Iservice {
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;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public boolean callPay(java.lang.String name, java.lang.String pwd, int money) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
_data.writeString(pwd);
_data.writeInt(money);
mRemote.transact(Stub.TRANSACTION_callPay, _data, _reply, 0);
_reply.readException();
_result = (0 != _reply.readInt());
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_callPay = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public boolean callPay(java.lang.String name, java.lang.String pwd, int money) throws android.os.RemoteException;
}
刚开始看整个java文件内心是拒绝的,里面方法很多,看起来显得杂乱无章。但是仔细分析下来发现逻辑还是很清晰的,一步步来看:
public static abstract class Stub extends android.os.Binder implements com.example.developmentarts.Iservice
该类继承自Binder并实现了Iservice接口,但未具体实现该接口的callPay()
方法,而是放到子类里面去实现。本例中在PayService中实现了callPay()
方法:
private class MyBinder extends Iservice.Stub {
@Override
public boolean callPay(String name, String pwd, int money) throws RemoteException {
return pay(name,pwd,money);
}
}
@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_callPay: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _arg1;
_arg1 = data.readString();
int _arg2;
_arg2 = data.readInt();
boolean _result = this.callPay(_arg0, _arg1, _arg2);
reply.writeNoException();
reply.writeInt(((_result) ? (1) : (0)));
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
首先会使用code来判断客户端请求的是什么方法,随后从data
中读取客户端传入的参数,然后调用this.callPay
方法,此callPay()
方法会调用服务端实现的callPay()
方法,从而完成方法的调用。最终得到返回值_result
,将其写入_reply
中。
注意到此方法会返回一个boolean
类型的值,当返回false
时,表示客户端请求失败。
callPay()
方法,该方法运行在客户端中。 /**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public boolean callPay(java.lang.String name, java.lang.String pwd, int money) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
_data.writeString(pwd);
_data.writeInt(money);
mRemote.transact(Stub.TRANSACTION_callPay, _data, _reply, 0);
_reply.readException();
_result = (0 != _reply.readInt());
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
当客户端调用服务端的callPay()
方法时,会创建一个Parcel对象_data
,将参数写入_data
对象中,然后调用mRemote.transact()
方法,该方法会使服务端调用onTransact()
方法,从而完成客户端对服务端方法的调用。
至此完成了对于生成的Iservice.java
文件的分析,实际上该java
文件完全可以读者自己写出来,使用Android Studio的AIDL来自动编译生成Iservice.java
文件方便了我们编写跨进程程序。
工程如下:android studio aidldemo