AIDL
AIDL是什么?
Android Interface Definition Language,安卓接口定义语言
前提阅读:Android基础——Service
AIDL内部实现——存取钱
在java同级目录下new-AIDL-AIDL File
命名为UserAction,系统自动生成UserAction.aidl
删除里面的注释和basicTypes(),定义两个方法,如果是自定义数据类型需要序列化,in表示输入
interface UserAction {
void saveMoney(in int money);
int getMoney();
}
创建UserActionAIDLImpl类实现UserAction.Stub重写两个方法
- 这里是extends UserAction.Stub,AS会根据AIDL生成一个class文件
- 如果报红实现不了则在菜单栏Build-make porject一下
public class UserActionAIDLImpl extends UserAction.Stub {
@Override
public void saveMoney(int money) throws RemoteException {
Log.d("TAG", "saveMoney: " + money);
}
@Override
public int getMoney() throws RemoteException {
return 100;
}
}
创建UserService在onBind()方法中返回UserActionAIDLImpl
public class UserService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new UserActionAIDLImpl();
}
}
在activity_main创建两个按钮
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/saveMoney"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="存钱" />
<Button
android:id="@+id/getMoney"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="取钱" />
</LinearLayout>
修改MainActivity绑定服务,在onServiceConnected()中通过UserAction.Stub.asInterface(service)获取UserAction实例,利用多态调用AIDL方法(可能会抛出异常)
public class MainActivity extends AppCompatActivity {
private Button mSaveBtn;
private Button mGetBtn;
private UserConnection mConnection;
private boolean mIsBind;
private UserAction mUserAction;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService();
initView();
initListener();
}
private void initListener() {
mSaveBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mUserAction.saveMoney(100);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
mGetBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mUserAction.getMoney();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private void initView() {
mSaveBtn = findViewById(R.id.saveMoney);
mGetBtn = findViewById(R.id.getMoney);
}
private void bindService() {
Intent intent = new Intent(MainActivity.this, UserService.class);
mConnection = new UserConnection();
mIsBind = bindService(intent, mConnection, BIND_AUTO_CREATE);
}
private class UserConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mUserAction = UserAction.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mIsBind && mConnection != null) {
unbindService(mConnection);
mConnection = null;
mIsBind = false;
}
}
}
AIDL跨应用实现——支付
Pay应用
AIDL接口
在项目Pay中创建回调PayResul.aidl
interface PayResult {
void onPaySuccsee();
void onPayFailed(in int errorCode,in String msg);
}
创建Pay.aidl,用到PayResult 需要手动import
import com.example.pay.PayResult;
interface Pay {
void requestPay(String orderInfo,float payMoney,PayResult callback);
}
Service及其Action
在Manifest中声明action和category
<service
android:name=".PayService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.pay.PAY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
创建PayService,内部类PayImpl实现Pay.Stub,PayService跳转到PayActivity
- 注意Service和Activity不能同一个栈,利用setFlags()创建新栈
- PayAction类用于与内部的Activity显示绑定
- PayImpl用于与外部的Activity隐式绑定
public class PayService extends Service {
private PayImpl mPayImpl;
@Override
public IBinder onBind(Intent intent) {
String action = intent.getAction();
if (action != null && "com.example.pay.PAY".equals(action)) {
mPayImpl = new PayImpl();
return mPayImpl;
}
return new PayAction();
}
public class PayAction extends Binder {
public void pay(float money) {
if (mPayImpl != null) {
//外部绑定成功后,进行实际支付操作,如开启事务,完事后回调结果
mPayImpl.paySuccess();
}
}
public void cancel() {
if (mPayImpl != null) {
mPayImpl.payFail(1, "cancel");
}
}
}
private class PayImpl extends Pay.Stub {
private PayResult mCallback;
@Override
public void requestPay(String orderInfo, float payMoney, PayResult callback) throws RemoteException {
this.mCallback = callback;
Intent intent = new Intent(PayService.this, PayActivity.class);
intent.putExtra("orderInfo", orderInfo);
intent.putExtra("payMoney", payMoney);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
public void paySuccess() {
try {
if (mCallback != null) {
mCallback.onPaySuccsee();
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void payFail(int error, String msg) {
if (mCallback != null) {
try {
mCallback.onPayFailed(error, msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
}
PayActivity及其布局
创建布局文件activity_pay.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".PayActivity">
<TextView
android:id="@+id/order_info"
android:hint="这里显示账单信息"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/pay"
android:text="确认支付"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
创建PayActivity绑定PayService用于弹出支付界面进行确认支付操作,这里支付成功后直接finish
public class PayActivity extends AppCompatActivity {
private boolean mIsBind;
private PayService.PayAction mPayAction;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pay);
doBindService();
initView();
}
@Override
public void onBackPressed() {
super.onBackPressed();
if (mPayAction != null) {
mPayAction.cancel();
}
}
private void initView() {
Intent intent = getIntent();
String orderInfo = intent.getStringExtra("orderInfo");
final float payMoney = intent.getFloatExtra("payMoney", 0);
TextView orderInfoTv = findViewById(R.id.order_info);
orderInfoTv.setText("账单是:" + orderInfo + ",金额是:" + payMoney);
Button payBtn = findViewById(R.id.pay);
payBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (payMoney < 100) {
Toast.makeText(PayActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
mPayAction.pay(payMoney);
finish();
} else {
Toast.makeText(PayActivity.this, "钱不够", Toast.LENGTH_SHORT).show();
}
}
});
}
private void doBindService() {
Intent intent = new Intent(this, PayService.class);
mIsBind = bindService(intent, mConnection, BIND_AUTO_CREATE);
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mPayAction = (PayService.PayAction) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mPayAction = null;
}
};
@Override
protected void onDestroy() {
if (mIsBind && mConnection != null) {
mIsBind = false;
unbindService(mConnection);
mConnection = null;
}
super.onDestroy();
}
}
demo0应用
AIDL
将Pay里面的aidl文件拷贝到demo0中并make project
MainActivity及布局
修改activity_main.xml,TextView用于显示支付结果,另有一支付按钮
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/payResult"
android:hint="这里返回支付结果"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/userPay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点击支付" />
</LinearLayout>
修改MainActivity,通过隐式意图绑定PayService获取返回的Pay实例,在按钮的点击事件中传入参数调用AIDL的支付操作,在回调中进行支付结果的处理
public class MainActivity extends AppCompatActivity {
private TextView mPayResultTv;
private Button mPayBtn;
private payConnection mPayConnection;
private boolean mIsBind;
private Pay mPay;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindPayService();
initView();
initListener();
}
private void bindPayService() {
Intent intent = new Intent();
intent.setAction("com.example.pay.PAY");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setPackage("com.example.pay");
mPayConnection = new payConnection();
mIsBind = bindService(intent, mPayConnection, BIND_AUTO_CREATE);
Log.d("TAG", "bindPayService: " + mIsBind);
}
private class payConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mPay = Pay.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("TAG", "onServiceDisconnected");
}
}
private void initListener() {
mPayBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
if (mPay != null) {
mPay.requestPay("黄焖鸡米饭", 15, new PayCallback());
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private class PayCallback extends PayResult.Stub {
@Override
public void onPaySuccess() throws RemoteException {
mPayResultTv.setText("支付成功,扣除金额");
Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onPayFailed(int errorCode, String msg) throws RemoteException {
mPayResultTv.setText("支付失败");
Toast.makeText(MainActivity.this, "支付失败", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mIsBind && mPayConnection != null) {
unbindService(mPayConnection);
mPayConnection = null;
mIsBind = false;
}
}
private void initView() {
mPayResultTv = findViewById(R.id.payResult);
mPayBtn = findViewById(R.id.userPay);
}
}
注意事项
- 在API 28/Android 9以前,代码可以运行
- 在API 29/Android 10以后,在MainActivity中通过隐私意图绑定不了其他应用的服务,且不会报明显错误
可通过在调用端(demo0)中的<manifest>标签下添加<queries>标签解决,package指定服务端(pay)的包名
<queries>
<package android:name="com.example.pay" />
</queries>
如添加后无法编译,则需要将AS和Gradle更到最新版本