某天下班在地铁上玩半年前写的扫雷小游戏的时候, 突然产生了一个想法, 能不能设计一套算法让游戏自动进行呢? 由程序来寻找最优解, 瞬间完成扫雷, 但是由于我对算法不太擅长, 能不能提供接口给外部, 让其他感兴趣的开发者来设计扫雷算法呢? 于是乎我想到了使用 AIDL 给外部提供接口, 由其他感兴趣的开发者来设计扫雷算法.
先贴下最后实现的效果(扫雷游戏apk下载地址 – 扫雷算法apk下载地址):
由 扫雷游戏 对外提供 aidl 接口, aidl 文件如下:
注意: 扫雷游戏与扫雷算法中的aidl文件必须完全一致, 最好直接复制过去, 否则有可能导致调用aidl接口得到错误的结果
// IMineAidlInterface.aidl
package com.eshel.mine.aidl;
/**
* 扫雷对外提供 AIDL 接口
*/
interface IMineAidlInterface {
String test();
/**
* 游戏开始与否
*/
boolean gameStarted();
/**
* 获取一行多少雷
*/
int getMinesWidth();
/**
* 获取一列多少雷
*/
int getMinesHeight();
/**
* 获取一个格子周围有几个未知格子
* 被标记旗子不计数, 被标记问号计数
*/
int getUnKnown(int x, int y);
/**
* 点击扫雷
* @return 变化的雷的集合, 格式为: x=y=mineNumber
* 角标为0的元素对应点击的那个
*/
List<String> clickMine(int x, int y);
/**
* 长按标记
*/
void longClickMine(int x, int y);
/**
* 0 - 8 代表 周围雷的数量
* -1代表本身是雷
* 10 代表 未知
* 11 代表被标记
* 12 代表 ? 标记
* -2 代表错误
*/
int lookMineType(int x, int y);
/**
* 0 游戏未开始
* 1 游戏进行中(已开始)
* -1 游戏结束 , Game Over You Lose
* 2 游戏结束, You Win
*/
int seeGameState();
}
扫雷游戏(数据提供者):
在AndroidStudio中通过右键 --> New --> AIDL --> AIDL File创建aidl文件, 文件创建完成点击同步生成java文件, 然后创建 Service文件, 通过 AIDL 生成的文件 IMineAidlInterface 使用匿名内部类的方式来创建 IBinder 对象, 并在此实现 aidl 接口, 固定写法, 代码如下:
注意: 在 MineAidlService 中实现的接口(如 gameStarted()等), 都会在子线程中被调用, 所以UI操作需要通过 Handler 发消息
AIDL默认支持8大基本类型, String类型, List Map类型, JavaBean需要实现 Parcelable , 其中 clickMine 方法由于数据结构简单所以直接使用了String类型, 想了解JavaBean怎么使用的自行百度 AIDL.
public class MineAidlService extends Service {
private IBinder mineBinder = new IMineAidlInterface.Stub() {
@Override
public boolean gameStarted() throws RemoteException {
boolean gameStarted = MineDataProvider.gameState == 1;
Log.i("Mine",gameStarted+"");
return gameStarted;
}
@Override
public int getMinesWidth() throws RemoteException {
return MineDataProvider.getMinesWidth();
}
@Override
public int getMinesHeight() throws RemoteException {
return MineDataProvider.getMinesHeight();
}
@Override
public int getUnKnown(int x, int y) throws RemoteException {
return MineDataProvider.getUnKnown(x, y);
}
@Override
public List<String> clickMine(int x, int y) throws RemoteException {
return MineDataProvider.clickMine(x,y);
}
@Override
public void longClickMine(int x, int y) throws RemoteException {
MineDataProvider.longClickMine(x,y);
}
@Override
public int lookMineType(int x, int y) throws RemoteException {
return MineDataProvider.lookMineType(x, y);
}
@Override
public int seeGameState() throws RemoteException {
return MineDataProvider.gameState;
}
@Override
public String test(){
return "扫雷 Demo";
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mineBinder;
}
}
接着, 需要在清单文件中注册这个服务:
注意: exported 代表是否可以被其他进程调用, 必须为 true, 意图过滤器是为了由其他APP通过隐式意图绑定服务
<service
android:exported="true"
android:name=".aidl.MineAidlService" >
<intent-filter>
<action android:name="com.eshel.mine.MineAidlService"/>
intent-filter>
service>
扫雷游戏的业务逻辑就不讲解了, 感兴趣的可以去 GitHub 查看源码 点这前往GitHub
提供数据的我称之为 服务端, 获取使用数据的称之为 客户端
到此为止服务端已经完成了AIDL, 接下来需要在客户端中使用 由服务端提供的AIDL接口.
首先要将服务端的aidl文件复制到客户端相同位置, 同步生成java代码.
然后在客户端的Activity中绑定远程服务:
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//远程服务以及连接成功, 初始化 mineProvider, 之后就可以使用 mineProvider 通过 aidl 调用服务器的数据了
mineProvider = IMineAidlInterface.Stub.asInterface(service);
Log.i(TAG, "onServiceConnected: success");
connected();
}
@Override
public void onServiceDisconnected(ComponentName name) {
mineProvider = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//扫雷游戏 Service 中配置的 Action
Intent intent1 = new Intent("com.eshel.mine.MineAidlService");
//扫雷游戏包名(Android 5.0 之后使用隐式意图调用服务必须加包名)
intent1.setPackage("com.eshel.mine");
//调用此行后如果目标App存在将会执行ServiceConnection中的onServiceConnected方法, 如果没有执行需检查配置是否有误
bindService(intent1, mConnection, BIND_AUTO_CREATE);
}
AIDL 使用方法都是固定代码, 需要注意的地方(我遇到的问题)再总结一遍:
AIDL 是通过 Binder 机制实现的, 但由于个人能力有限无法讲解Binder机制, 推荐一篇博文 https://blog.csdn.net/carson_ho/article/details/73560642 对Binder的讲解的非常清晰
关于扫雷的算法我觉得还是有可以优化的地方的, 想要了解扫雷算法的可以到GitHub查看源码(文章开头的 GitHub 地址), 感兴趣的可以使用扫雷游戏提供的 aidl 接口自己写下扫雷算法. (Gif 图中刚开始随机点击比较慢是因为我调试时 将每次随机点击都 sleep 了 1000ms)