文章目录
- 问题1:Service Intent must be explicit
- 问题2:AIDL连接不上
- 问题3:AIDL找不到自定义类
- AIDL支持的默认数据类型
- AIDL中使用自定义数据类型
- 资源下载
学习【达内课程】AIDL(上)中我们遇到了几个坑。这里来说一下。
问题1:Service Intent must be explicit
解决办法
最开始我们在【ClientProject】中绑定 Service 中代码是这样写的:
Intent intent = new Intent("com.example.serviceapplication.WORK_SERVICE");
conn = new InnerServiceConnection();
bindService(intent,conn,BIND_AUTO_CREATE);运行程序,点击绑定按钮就会这个错,所以根据解决办法,我们改为:
Intent intent = new Intent();
intent.setAction("com.example.serviceapplication.WorkService");
intent.setPackage("com.example.serviceapplication");
conn = new InnerServiceConnection();
bindService(intent, conn, BIND_AUTO_CREATE);其中setAction() 后的字符串是【ServerProject】中 AndroidManifest.xml 中的字符串相同。
其中 setPackage() 后边的字符串是 【ServerProject】的包名。
问题2:AIDL连接不上
如果你的手机是 Android 11,【ClientProject】MainActivity 中的 player 变量可能为空。也就是点击绑定 Service 的时候,如果你 debug 会发现InnerServiceConnection类中的onServiceConnected方法始终没走。
解决办法1:改成 api 29
解决办法2:
如果您的应用以 Android 11(API 级别 30)或更高版本为目标平台,并且需要与应用(自动可见的应用除外)交互,请在您应用的清单文件中添加 <queries> 元素。在 <queries> 元素中,按软件包名称、按 intent 签名或按提供程序授权指定其他应用
在 client 端 AndroidManifest.xml 添加 queries 包。例如咱们的这个项目,就需要在【ClientProject】的 AndroidManifest.xml 中添加
<queries>
<package android:name="com.example.serviceapplication" />
</queries>后边 name 的值就是 【ServerProject】的包名。
问题3:AIDL找不到自定义类
这个问题在下面自定义类的时候会遇到。解决办法:
在 app 下的 build.gradle 中 android 的节点下添加
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/aidl']
resources.srcDirs = ['src/main/java', 'src/main/aidl']
aidl.srcDirs = ['src/main/aidl']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
}
}ServerProject 和 ClientProject 都需要添加。
解决了这些问题,我们接着学习 AIDL 的其他内容。
AIDL支持的默认数据类型
AIDL 接口中默认支持的数据类型有
1、除了short之外的基本数据类型
2、String和CharSequence 3、List和Map
AIDL中使用自定义数据类型
如果需要在 AIDL 中使用自定义的数据类型,必须实现Parcelable接口
开发步骤
1、自定义类,实现 Parcelable 接口,例如 Music.java
2、创建 Music.java 对应的aidl文件,即Music.aidl,使用与 Music.java 相同的 package 语句声明所在包,并使用parcelable Music;语法声明这是一个 Parcelable 类型的数据
在使用 Music 类型的 aidl 接口文件中,使用import语句显式的导包,导入 Music 类型,注意:无论aidl接口文件与 Music 是否在同一个包中,都必须导包。
3、将服务端的 aidl 接口文件、Music 的 java 文件、Music 的 aidl 全部复制到客户端
举个栗子
例如,我们要支持自定义的 Music 类。我们按照上面的步骤开发。
1、我们自定义一个Music类,并实现 Parcelable接口
我们把这个类放到和 IMusicPlayer.aidl 同级的目录下。
public class WorkService extends Service {
public WorkService() {
}
public IBinder onBind(Intent intent) {
InnerBinder binder = new InnerBinder();
return binder;
}
private class InnerBinder extends IMusicPlayer.Stub {
public void play() throws RemoteException {
Log.d("AIDL", "[Server]WorkService$InnerBinder play()");
}
public void pause() throws RemoteException {
Log.d("AIDL", "[Server]WorkService$InnerBinder pause()");
}
public int getDuration() throws RemoteException {
Log.d("AIDL", "[Server]WorkService$InnerBinder getDuration()-->9527");
return 9527;
}
public Music getMusic() throws RemoteException {
Music music = new Music();
music.title = "Stronger";
music.artist = "Glee";
music.duration = 203000;
return music;
}
}
}2、创建 Music.java 对应的aidl文件:Music.aidl
创建IMusic.aidl文件
package com.example.serviceapplication;
parcelable Music;在 IMusicPlayer.aidl中,导包,导入 Music.aidl。写一个返回值为 Music 的方法进行测试。
// IMusicPlayer.aidl
package com.example.serviceapplication;
import com.example.serviceapplication.Music;
interface IMusicPlayer {
void play();
void pause();
int getDuration();
Music getMusic();
}运行程序会报错,因为 WorkService 中需要重写新的方法
private class InnerBinder extends IMusicPlayer.Stub {
......
public Music getMusic() throws RemoteException {
Music music = new Music();
music.title = "Stronger";
music.artist = "Glee";
music.duration = 203000;
return music;
}
}
}3、把【ServerProject】中的 IMusicPlayer.aidl、Music.aidl、Music 类复制到客户端。
activity_main 中增加1个按钮用来测试 getMusic() 这个方法。
<Button
android:id="@+id/btn_getMusic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="调用getGetMusic()方法" />MainActivity
private View btnGetMusic;//调用服务端的getMusic方法
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
......
btnGetMusic = findViewById(R.id.btn_getMusic);
......
btnGetMusic.setOnClickListener(this);
}
public void onClick(View view) {
switch (view.getId()) {
......
case R.id.btn_getMusic:
try {
Music music = player.getMusic();
Log.d("AIDL","[Client] getMusic()-->歌曲名:"+music.title+";演唱者:"+music.artist+";歌曲时长;"+music.duration);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}运行 Server 和 Client,点击绑定 Service 按钮,然后点击getMusic()方法的按钮
观察日志
资源下载
源码下载
