Android AIDL示例-回调方法版
Posted Jason_Lee155
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android AIDL示例-回调方法版相关的知识,希望对你有一定的参考价值。
概述
AIDL是一个缩写,全称是android Interface Definition Language,也就是Android接口定义语言,它是用来实现进程间通讯的,本文使用AIDL写一个小demo来实现夸进程间通讯
AIDL介绍
- 文件类型:用aidl书写的文件的后缀是.aidl
- 数据类型:基本类型, 字符串类型(String&CharSequence), List, Map, Parcelable, AIDL接口共六种
- AIDL文件类型:1:定义parcelable对象,以供其他AIDL文件使用AI
AIDL
首先定义一个音乐的类型Music类,并实现Parcelable接口。想要AIDL传输数据,需要实现这个接口。
public class Music implements Parcelable {
public String name; //书名
public String author; //作者
public Music(String name ,String author){
this.name = name;
this.author = author;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
dest.writeString(this.author);
}
public Music() {
}
protected Music(Parcel in) {
this.name = in.readString();
this.author = in.readString();
}
public static final Parcelable.Creator<Music> CREATOR = new Parcelable.Creator<Music>() {
@Override
public Music createFromParcel(Parcel source) {
return new Music(source);
}
@Override
public Music[] newArray(int size) {
return new Music[size];
}
};
@Override
public String toString() {
return "音乐名称:"+name +" 歌手:"+author;
}
}
然后看相关的aidl的music类
package rock.pp.com.aidl_demo;
parcelable Music;
注意:aidl的Music和java的Music的包名必须一致
下面添加AIDL的接口,是一个接口类用于监听新音乐的到达的接口
package rock.pp.com.aidl_demo;
import rock.pp.com.aidl_demo.Music;
interface INewMusicArrivedListener {
void onNewBookArrived(in Music newMusic);
}
下面是音乐管理类的AIDL接口,用来管理音乐的,这个类是进程间通讯的核心类,主要有四个方法,1:获取音乐类别 2:添加音乐 3:注册接口 4:注销接口
package rock.pp.com.aidl_demo;
// Declare any non-default types here with import statements
import rock.pp.com.aidl_demo.Music;
import rock.pp.com.aidl_demo.INewMusicArrivedListener;
interface IMusicManager {
List<Music> getMusicList(); // 返回书籍列表
void addMusic(in Music music); // 添加书籍
void registerListener(INewMusicArrivedListener listener); // 注册接口
void unregisterListener(INewMusicArrivedListener listener); // 注销接口
}
所有的自定义的参数都需要标注参数方向, in表示输入类型, out表示输出类型, inout表示输入输出类型. out与inout的开销较大, 根据实际需要再用.
AIDL文件通过编译会自动生成对应的java文件,服务端和客户端操作的就是对应的java文件
如上图所以,蓝色框内是我们定义的AIDL文件,红色框内是自动编译生成的java文件
服务端
下面我们看下服务端的代码
/**
* 音乐管理的服务类
*/
public class MusicManagerService extends Service {
private static final String TAG = MusicManagerService.class.getSimpleName();
private ArrayList<Music> mMusicList = new ArrayList<>(); //生成的音乐列表
private List<INewMusicArrivedListener> mListenerList = new ArrayList<>(); //客户端注册的接口列表
private boolean isServiceDestroy = false; //当前服务是否结束
private int num = 0;
/**
* 解绑服务
* @param conn
*/
@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
Log.e(TAG,"unbindService-----");
}
/**
* 服务端通过Binder实现AIDL的IMusicManager.Stub接口
* 这个类需要实现IMusicManager相关的抽象方法
*/
private Binder mBinder = new IMusicManager.Stub() {
@Override
public List<Music> getMusicList() throws RemoteException {
SystemClock.sleep(1000); // 延迟加载
return mMusicList;
}
@Override
public void addMusic(Music music) throws RemoteException {
mMusicList.add(music);
}
@Override
public void registerListener(INewMusicArrivedListener listener) throws RemoteException {
mListenerList.add(listener);
int num = mListenerList.size();
Log.e(TAG, "添加完成, 注册接口数: " + num);
}
@Override
public void unregisterListener(INewMusicArrivedListener listener) throws RemoteException {
mListenerList.add(listener);
int num = mListenerList.size();
Log.e(TAG, "添加完成, 注册接口数: " + num);
}
};
//新音乐到达后给客户端发送相关通知
private void onNewMusicArrived(Music music) throws Exception {
mMusicList.add(music);
Log.e(TAG, "发送通知的数量: " + mMusicList.size());
int num = mListenerList.size();
for (int i = 0; i < num; ++i) {
INewMusicArrivedListener listener = mListenerList.get(i);
listener.onNewBookArrived(music);
}
for (Music b : mMusicList){
Log.e(TAG,b.name+" "+b.author);
}
}
@Override public void onCreate() {
super.onCreate();
Log.e(TAG,"onCreate-------------");
//首先添加两首歌曲
mMusicList.add(new Music("《封锁我一生》", "王杰"));
mMusicList.add(new Music("《稻香》", "周杰伦"));
//音乐制造机器
new Thread(new ServiceWorker()).start();
}
@Override public void onDestroy() {
isServiceDestroy = true;
super.onDestroy();
Log.e(TAG,"onDestroy-----");
}
//音乐制造机
//每5秒生产一首音乐
private class ServiceWorker implements Runnable {
@Override public void run() {
while (!isServiceDestroy) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
num++;
if (num == 5) {
isServiceDestroy= true;
}
Message msg = new Message();
mHandler.sendMessage(msg); // 向Handler发送消息,更新UI
}
}
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
int id = 1 + mMusicList.size();
Music music = new Music("《张学友——新歌》"+id, "张学友");
try {
onNewMusicArrived(music);
} catch (Exception e) {
e.printStackTrace();
}
}
};
@Nullable @Override public IBinder onBind(Intent intent) {
return mBinder;
}
}
如上所示,我们通过IMusicManager.Stub生成进程间通讯的binder类,然后新启一个线程动态生成音乐,然后告知客户端
客户端
下面我们看下客户端的代码:这里需要注意,回调接口在客户端注册,目的是为了让服务端拿到回调接口,通知客户端。客户端拿到的是服务端的代理,注册回调可看作服务端收到回调listener。
private TextView music_list;
private IMusicManager mRemoteMusicManager; //音乐管理类 通过aidl文件编译生成的java类
//监听新音乐的到达的接口
private INewMusicArrivedListener musicArrivedListener = new INewMusicArrivedListener.Stub() {
/**
* 服务端有新音乐生成
* @param newMusic
* @throws RemoteException
*/
@Override
public void onNewBookArrived(Music newMusic) throws RemoteException {
mHandler.obtainMessage(MESSAGE_ARRIVED, newMusic ).sendToTarget();
}
};
private Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_ARRIVED:
Log.e(TAG, "收到的新书: " + msg.obj);
new BookListAsyncTask().execute();
break;
default:
super.handleMessage(msg);
break;
}
}
};
//绑定服务时的链接参数
private ServiceConnection mConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) {
IMusicManager musicManager = IMusicManager.Stub.asInterface(service);
try {
mRemoteMusicManager = musicManager;
Music newMusic = new Music("《客户端音乐》", "rock");
musicManager.addMusic(newMusic);
musicManager.registerListener(musicArrivedListener);
new BookListAsyncTask().execute();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override public void onServiceDisconnected(ComponentName name) {
mRemoteMusicManager = null;
Log.e(TAG, "绑定结束");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
music_list = findViewById(R.id.music_list);
}
/**
* 获取music列表
*
* @param view 视图
*/
public void getMusicList(View view) {
if (mRemoteMusicManager !=null){
List<Music> list = null;
try {
list = mRemoteMusicManager.getMusicList();
}catch (Exception e){
}
if (list!=null){
String content = "";
for (int i = 0; i < list.size(); ++i) {
content += list.get(i).toString() + "\\n";
}
music_list.setText(content);
}
}
Toast.makeText(getApplicationContext(), "正在获取中...", Toast.LENGTH_SHORT).show();
}
/**
* 绑定服务按钮的点击事件
*
* @param view 视图
*/
public void bindService(View view) {
Intent intent = new Intent(this, MusicManagerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
/**
* 解绑服务
*/
public void unbindService(View view){
unbindService(mConnection);
}
private class BookListAsyncTask extends AsyncTask<Void, Void, List<Music>> {
@Override
protected List<Music> doInBackground(Void... params) {
List<Music> list = null;
try {
list = mRemoteMusicManager.getMusicList();
} catch (RemoteException e) {
e.printStackTrace();
}
return list;
}
@Override
protected void onPostExecute(List<Music> musicList) {
String content = "";
for (int i = 0; i < musicList.size(); ++i) {
content += musicList.get(i).toString() + "\\n";
}
music_list.setText(content);
}
}
客户端代码如上 ,我们绑定一个服务 ,然后注册一个新音乐到达的接口,当服务端有新音乐生成的时候就会触发这个接口。
效果图如上。
到此进程间通讯的demo基本就完成了
demo地址:github.com/syg13579/an…
以上是关于Android AIDL示例-回调方法版的主要内容,如果未能解决你的问题,请参考以下文章