AIDL的作用

1.aidl 是Android interface definition Language 的英文缩写,意思Android 接口定义语言。

2.使用aidl 可以帮助我们发布以及调用远程服务,实现跨进程通信。

在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,Java中是不支持跨进程内存共享的。因此要传递对象, 需要把对象解析成操作系统能够理解的数据格式, 以达到跨界对象访问目的。

3.将服务的aidl 放到对应的src 目录,工程的gen 目录会生成相应的接口类。

在JavaEE中,采用RMI通过序列化传递对象。在Android中, 则采用AIDL方式实现。 AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC)。AIDL的IPC 机制和EJB所采用的CORBA很类似,进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应 的对象。

由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员 来说是透明的。

AIDL中的数据类型

  1. 除了short以外的7种基本数据类型
  2. String和CharSequence
  3. List和Map,在使用这2种集合时,必须声明为in、out或inout
  4. Parcelable类型

在AIDL中使用自定义数据类型

  1. 在自定义数据类型Music中实现Parcelable接口
  2. 创建自定义数据类型的aidl文件,例如Music.aidl,内容例如:
    package xx.xx.xx.xx;
    parcelable Music;
    以上代码中,package语句保持与Music.java完全相同
  3. 在使用了该类型的AIDL接口文件中,使用import语句显式的导包,即使是同包的也必须导包
  4. 将Music.java、Music.aidl及使用了Music类型的AIDL接口文件全部复制并粘贴到客户端

1.[S]创建WorkService类,继承自android.app.Service,并注册,且注册时,为节点配置子级,使得该Service是可以被隐式激活的

<service android:name="cn.tedu.aidl_server.WorkService" >
            <intent-filter>
                <action android:name="tedu.intent.action.WORK_SERVICE"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>
  1. [S]使用AIDL语法创建IMusicPlayer接口,并在接口中定义那些由Service去实现功能,却由Activity调用的方法,例如:
    – void playMusic()
    – void pauseMusic()
    – boolean isPlaying()
//服务端IMusicPlayer.aidl
package cn.tedu.aidl_server;
import cn.tedu.aidl_server.Music;

interface IMusicPlayer {
    void play();

    void pause();

    boolean isPlaying();

    Music getMusic();
}

3.[S][WorkService] 定义内部类InnerBinder,继IMusicPlayer .Stub,并重写抽象方法
4.[S][WorkService] 在onBind()方法中,创建InnerBinder的对象,并作为该方法的返回值

package cn.tedu.aidl_server;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class WorkService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        InnerBinder binder = new InnerBinder();
        return binder;
    }

    private class InnerBinder extends IMusicPlayer.Stub {

        @Override
        public void play() throws RemoteException {
            Log.i("tedu", "[Server] WorkService$InnerBinder.play()");
        }

        @Override
        public void pause() throws RemoteException {
            Log.i("tedu", "[Server] WorkService$InnerBinder.pause()");
        }

        @Override
        public boolean isPlaying() throws RemoteException {
            boolean result = true;
            Log.i("tedu", "[Server] WorkService$InnerBinder.isPlaying() -> " + result);
            return result;
        }

        @Override
        public Music getMusic() throws RemoteException {
            Music music = new Music();
            music.artist = "张学友";
            music.title = "雪狼湖";
            music.duration = 9527;
            Log.i("tedu", "[Server] WorkService$InnerBinder.getMusic() -> " + music);
            return music;
        }

    }

}
  1. [C][MainActivity] 定义内部类InnerServiceConnection,实现androi.content.ServiceConnection,并添加实现2个抽象方法
  2. [C][MainActivity] 当需要绑定Service时,调用bindService()方法,第1个参数是Intent对象,用于隐式指定被激活的Service组件,第2个参数是InnerServiceConnection的对象,且该对象必须声明为全局变量,便于后续解绑,第3个参数是Context.BIND_AUTO_CREATE常量
  3. [C][MainActivity] 声明全局变量IMusicPlayer player,在InnerServiceConnection类的onServiceConnected()方法中,调用IMusicPlayer.Stub.asInterface()方法,将第2个参数IBinder service作为asInterface()方法的参数,返回值赋值给player
package cn.tedu.aidl_client;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.widget.Toast;
import cn.tedu.aidl_server.IMusicPlayer;
import cn.tedu.aidl_server.Music;

public class MainActivity extends Activity implements View.OnClickListener {
    private View btnBindService;
    private View btnCallPlay;
    private View btnCallPause;
    private View btnCallIsPlaying;
    private View btnCallGetMusic;
    private ServiceConnection conn;
    private IMusicPlayer player;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnBindService = findViewById(R.id.btn_bind_service);
        btnCallPlay = findViewById(R.id.btn_call_play);
        btnCallPause = findViewById(R.id.btn_call_pause);
        btnCallIsPlaying = findViewById(R.id.btn_call_is_playing);
        btnCallGetMusic = findViewById(R.id.btn_call_get_music);

        btnBindService.setOnClickListener(this);
        btnCallPlay.setOnClickListener(this);
        btnCallPause.setOnClickListener(this);
        btnCallIsPlaying.setOnClickListener(this);
        btnCallGetMusic.setOnClickListener(this);
    }

    @Override
    protected void onDestroy() {
        unbindService(conn);

        super.onDestroy();
    }

    private class InnerServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(
                ComponentName name, 
                IBinder service) {
            player = IMusicPlayer.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_bind_service:
            Intent service = new Intent();
            service.setAction("tedu.intent.action.WORK_SERVICE");
            conn = new InnerServiceConnection();
            int flags = BIND_AUTO_CREATE;
            bindService(service, conn, flags);
            break;

        case R.id.btn_call_play:
            if (player == null) {
                Toast.makeText(this, "请先绑定Service!!!", Toast.LENGTH_SHORT).show();
            } else {
                try {
                    player.play();
                    Toast.makeText(this, "调用成功!", Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            break;

        case R.id.btn_call_pause:
            if (player == null) {
                Toast.makeText(this, "请先绑定Service!!!", Toast.LENGTH_SHORT).show();
            } else {
                try {
                    player.pause();
                    Toast.makeText(this, "调用成功!", Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            break;

        case R.id.btn_call_is_playing:
            if (player == null) {
                Toast.makeText(this, "请先绑定Service!!!", Toast.LENGTH_SHORT).show();
            } else {
                try {
                    boolean result = player.isPlaying();
                    Toast.makeText(this, "调用成功! -> " + result, Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            break;

        case R.id.btn_call_get_music:
            if (player == null) {
                Toast.makeText(this, "请先绑定Service!!!", Toast.LENGTH_SHORT).show();
            } else {
                try {
                    Music music = player.getMusic();
                    Toast.makeText(this, "调用成功! -> " + music, Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            break;
        }
    }
}

源码下载地址:

lypeer 原码分析:http://www.jianshu.com/p/0cca211df63c