根据上一篇 Android开源项目之Music (一)--- MusicBrowserActivity 提到的,要继续往下分析源代码的话,需要具备AIDL的知识,如果有这方面知识的大神们请自行跳过,废话不多说,现在就进行AIDL的简单学习
一.什么是AIDL,AIDL的作用
AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。
由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。
通过代码来实现这个数据传输过程是冗长乏味的,Android提供了AIDL工具来处理这项工作。
如果有做过C#方面开放的,我想做个比喻,个人觉得这个AIDL很像C#里面提到的dll, 在“服务器”端有一份,在“客户端”也有一份,然后就可以调用了
(不知道这种比喻对不对,勿喷!)
二.AIDL的工作原理解析(直接写个demo)
1.居然要写远程服务进行进程间通信的话,那我们先在workspace下面建立两个工程,分别为AIDLServer和AIDLClient
2.在AIDLServer的包com.example.aidlserver下new一个文件IMyMusicPlayerService.aidl,写入以下代码.
package com.example.aidlserver;//注意一定要加入这个包名
interface IMyMusicPlayerService {//这个aidl的写法就是写一个interface一样,但是不需要加入修饰符public什么的
void play();//播放音乐
void stop();}
Ctrl + S 保存后 ADT 会根据这个IMyMusicPlayerService.aidl文件自动生成IMyMusicPlayerService.java文件。如同R.java文件一样在“gen/包名”下,代码是自动生成的,不要手动修改这个文件
3.由于我们要分析的是Music项目源码,所以我们搞一个专门用于播放音乐的Service吧.
这里首先需要有点Service和Binder的知识,在生成的.java文件中有个静态类
/** Local-side IPC implementation stub class. */public static abstract class Stubextends android.os.Binderimplementscom.example.aidlserver.IMyMusicPlayerService
Sub类它继承于Binder,引用了IMyMusicPlayerService接口,一个类继承了Binder,如果远程进程获得了
这个类的对象,那么它的对象就可以被远程的进程使用。
4.在res文件夹下,建立一个raw文件夹,下面放一首.mp3歌曲。接下来让我们编写这个Service类,MyMusicPlayerService
package com.example.aidlserver;
import java.io.FileDescriptor;
import java.io.IOException;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
/*
* 播放音乐服务类
* 2013年8月7日14:20:27
* Author: 胖虎
* http://blog.csdn.net/ljphhj
* */
public class MyMusicPlayerService extends Service{
//Logger TAG
public static final String LogTAG = "com.example.aidlserver.MyMusicPlayerService";
//android自带播放音乐类: android.media.MediaPlayer
private MediaPlayer mPlayer = null;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
if (mPlayer == null)
{
mPlayer = new MediaPlayer();
//得到音乐资源
FileDescriptor fildDescriptor = getResources().openRawResourceFd(R.raw.love).getFileDescriptor();
try {
//设置数据源
mPlayer.setDataSource(fildDescriptor);
//设置是否循环播放
mPlayer.setLooping(true);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
if (mPlayer != null)
{
//释放资源
mPlayer.release();
}
return super.onUnbind(intent);
}
/**
* 实现了接口中的两个函数
*/
private IBinder mBinder = new IMyMusicPlayerService.Stub() {
@Override
public void stop() throws RemoteException {
// TODO Auto-generated method stub
if (mPlayer.isPlaying())
{
//停止播放
mPlayer.stop();
}
}
@Override
public void play() throws RemoteException {
// TODO Auto-generated method stub
try {
if (!mPlayer.isPlaying())
{
mPlayer.prepare();
mPlayer.start();
}
} catch (Exception e) {
// TODO: handle exception
Log.i(LogTAG, "play函数出现异常");
}
}
};
}
并在AndroidManifest.xml文件中进行注册
<service
android:name="com.example.aidlserver.MyMusicPlayerService"
android:process=":remote"
>
<intent-filter >
<action android:name="com.example.aidlserver.MyMusicPlayerService"/>
</intent-filter>
</service>
5.这样服务器端所要做的就做完了,现在编写客户端,客户端的话,需要得到服务器端的aidl文件,当然这个aidl所在的包是不能被改变的,也就是说我们需要把整个aidl放在一个包名依旧为com.example.aidlserver的包下才可以.
布局文件就写两个“Button”按钮,我就不发上来了,下面看看这个AIDLClientActivity.java文件
package com.example.aidlclient;
import com.example.aidlserver.IMyMusicPlayerService;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
* AIDL demo 客户端
* @author 胖虎
*
*/
public class AIDLClientActivity extends Activity {
//Logger TAG
public static final String LogTAG = "com.example.aidlclient.AIDLClientActivity";
// 服务端 AndroidManifest.xml中的service中intent-filter的action声明的字符串
public static final String ACTION = "com.example.aidlserver.MyMusicPlayerService";
private Button playButton = null;
private Button stopButton = null;
private IMyMusicPlayerService mService = null;
private boolean isBinded = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
/*Service断开连接时,调用*/
@Override
public void onServiceDisconnected(ComponentName name) {
isBinded = false;
mService = null;
}
/*Service连接时,调用*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IMyMusicPlayerService.Stub.asInterface(service);
isBinded = true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidlclient);
/*service绑定的知识,不了解的可以网上找找*/
Intent intent = new Intent(ACTION);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
/*初始化View*/
initComponent();
}
/*解除Service绑定(此demo中没调用)*/
public void unBind()
{
if (isBinded)
{
unbindService(serviceConnection);
mService = null;
isBinded = false;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.aidlclient, menu);
return true;
}
private void initComponent()
{
playButton = (Button) findViewById(R.id.play);
stopButton = (Button) findViewById(R.id.stop);
playButton.setOnClickListener(buttonClickListener);
stopButton.setOnClickListener(buttonClickListener);
}
private OnClickListener buttonClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.play:
{
if (mService != null)
{
try {
mService.play();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
break;
case R.id.stop:
{
if (mService != null)
{
try {
mService.stop();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
break;
default:
break;
}
}
};
}
总结一下所有的步骤:
demo源码下载地址:
http://download.csdn.net/detail/u011133213/5885661