AIDL实现远程服务

一、定义

AIDl:android interface define language 安卓接口定义语言,这是一种新的语言,它可以被编译器自动编译为java语言,具体方法为在应用项目java文件夹中:
“New –> File –> AIDL”
然后定义自己需要用到的接口方法,点击:
“Build -> Make Project”
然后在Project视图下的“\app\build\generated\source\aidl\debug\项目文件目录”中可以看到相应的java文件

二、作用

为了解决进程间通讯,定义了两个应用程序之间的通讯规则。
他和接口非常的相似,我们可以先定义接口,再把接口修改为aidl.java –> .aidl (老版Eclipse可以这么做,现在我们用Android Studio可以参考上面的方式创建aidl)

aidl语言有自己的语法:
1 它可以识别java里面的基本数据类型
2 它无法识别访问修饰符 public private
3 它无法识别domain
如果要让aidl识别domain (实体类)
1 class Student implements Parcelable
2 写一个Student.aidl文件
package cn.itcast.domain;
parcelable Student;

aidl 自动生成.java文件后,我们使用什么?
Stub
asInterface(IBinder) IStudent
底层其实走的是代理机制。

aidl 就是一个合同 一式两份,写完aidl之后,把aidl所有的内容带包一起复制到客户端

三、本地服务的实现

绑定本地服务

在介绍可以实现远程服务的aidl之前,我们先讲一下本地服务的实现方式。本地服务就是在同一个应用中,使用绑定服务实现的一种方式。我们要了解一下为什么要绑定服务,其实绑定服务可以帮助我们调用服务里面的方法,下面我们举一个案例加以说明:

案例

AIDL实现远程服务_第1张图片
需求是通过Activity中的查询按钮,调用服务的queryNameById(int id)方法进行查询并返回到Activity当中,那么接下来就是代码的完善了~
1、订阅接口

/**
 * 接口
 * 接口的抽取:有什么样的行为,就抽取什么样的方法
 * @author apple
 *
 */
public interface IStudentListener {

    //根据学号查询学生的姓名
    public String queryNameById(int id);

}   

2、服务

public class MyService extends Service {

    private String[] names = new String[]{"张学友","刘德华","黎明","郭富城"};

    //增强版IBinder(真实的对象)
    private MyBinder ibinder = new MyBinder();

    @Override
    public IBinder onBind(Intent intent) {
        return ibinder;
    }


    //创建一个增强版的IBinder类
    private class MyBinder extends Binder implements IStudentListener{

        @Override
        public String queryNameById(int id) {
            //id只能是1 到4
            if(id <= 0 || id > names.length){
                return "苍姐姐";
            }else{
                return names[id-1];
            }
        }

    }
}

3、客户端

public class MainActivity extends Activity {

    private EditText et_id;
    private Button bt_query;
    private TextView tv_name;
    private MyServiceConnection conn;
    private IStudentListener iStudentListener;

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

        et_id = (EditText) findViewById(R.id.et_id);
        bt_query = (Button) findViewById(R.id.bt_query);
        tv_name = (TextView) findViewById(R.id.tv_name);

        //绑定服务
        conn = new MyServiceConnection();
        bindService(new Intent(this,MyService.class), conn, BIND_AUTO_CREATE);
    }

    private class MyServiceConnection implements ServiceConnection{

        //绑定成功
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            bt_query.setEnabled(true);
            //把IBinder对象转化成接口对象
            iStudentListener = (IStudentListener) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }

    }

    public void query(View v){
        //绑定服务(为什么服务的绑定需要时间)
        String idStr = et_id.getText().toString().trim();
        if(TextUtils.isEmpty(idStr)){
            Toast.makeText(this, "姐姐 学号不能为空", 0).show();
        }else{
            int id = Integer.parseInt(idStr);
            //调用接口对象的方法(就是调用真实对象的方法)
            String name = iStudentListener.queryNameById(id);
            tv_name.setText(name);
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
}

AIDL实现远程服务_第2张图片

四、AIDL实现远程服务

案例

AIDL实现远程服务_第3张图片

实现

1、创建aidl文件
首先还是先要创建aidl文件,文件名为:IStudentListener.aidl,具体可以参考这篇博客android studio使用aidl

2、服务器

/**
 * 远程的服务(在其他应用程序里面的服务)
 * @author apple
 *
 */
public class MyService extends Service {

    private String[] names = new String[]{"张学友","刘德华","黎明","郭富城"};

    private MyBinder ibinder = new MyBinder();

    @Override
    public IBinder onBind(Intent intent) {
        return ibinder;
    }

    //增强版的IBinder
    private class MyBinder extends IStudentListener.Stub{

        @Override
        public String queryNameById(int id) throws RemoteException {
            //id只能是1 到4
            if(id <= 0 || id > names.length){
                return "苍姐姐";
            }else{
                return names[id-1];
            }
        }
    }
}

AndroidManifest.xml我们需要添加这样的配置:
其中,intent-filter的作用是便于隐式调用该Service.

<service android:name=".MyService">
    <intent-filter>
         <action android:name="cn.itcast.action.studentquerysystem.server" />
service>

3、客户端(可以创建一个moudle、或者另外创建一个项目)
从服务器端把aidl文件带包一起复制过来,这里有坑,需要做的是我们复制过来,而不是自己手动新建aidl文件夹和文件,不然会报个莫名其妙的error……

public class MainActivity extends Activity {

    private EditText et_id;
    private TextView tv_name;
    private MyServiceConnection conn;
    private IStudentListener iStudentListener;

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

        et_id = (EditText) findViewById(R.id.et_id);
        tv_name = (TextView) findViewById(R.id.tv_name);
        //绑定服务
        Intent service = new Intent();
        service.setAction("cn.itcast.action.studentquerysystem.server");
        conn = new MyServiceConnection();
        bindService(service, conn, BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }

    private class MyServiceConnection implements ServiceConnection{

        //绑定的服务是一个远程的服务,传递过来的对象是个代理对象,而代理对象不能直接使用
        //需要使用Stub里面的一个方法:asInterface()把代理对象转化成真实对象再使用
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //把代理对象转化成真实对象
            iStudentListener = MyService.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }

    public void query(View v){
        String idStr = et_id.getText().toString().trim();
        if(TextUtils.isEmpty(idStr)){
            Toast.makeText(this, "姐姐 学号不能为空", 0).show();
        }else{
            int id = Integer.parseInt(idStr);
            //调用接口对象的方法(就是调用真实对象的方法)
            try {
                String name = iStudentListener.queryNameById(id);
                tv_name.setText(name);
            } catch (RemoteException e) {
                e.printStackTrace();
                Toast.makeText(this, "服务器端出现了错误", 0).show();
            }
        }
    }
}

AIDL实现远程服务_第4张图片

总结

这样,简单的跨应用的远程服务用AIDL就这样解决了,如果你还要在aidl文件中传入引用类型对象,就需要这个对象继承Parcelable接口,还需要在该aidl文件夹新建一个同名的aidl文件,例如我们需要一个Book对象,我们就要先创建一个Book.aidl文件。好啦先这样吧~

你可能感兴趣的:(android-开发,安卓基础)