AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言.
设计这门语言的目的是为了实现进程间通信,尤其是在涉及多进程并发情况下的进程间通信。
学习这个是在Service的远程服务调用时会遇到这个问题。
service的调用分本地调用和远程服务调用。本地其实就是同一个应用之间的调用,远程服务调用就是不同应用之间的调用。比如淘宝里的芭芭农场调用支付宝里的芭芭农场,是两个应用之间的调用。
案例:
客户端
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/button1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="bindRemoteService" android:text="bind remote Service" /> <EditText android:id="@+id/et_aidl_id" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="学员ID" android:text="3" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="invokeRemote" android:text="调用远程服务端的方法" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="unbindRemoteService" android:text="unbind remote Service" /> </LinearLayout>
服务端,由于是暴露服务,是不用界面的,只要编写好AIDL文件,拷贝一份到客户端,就可以进行调用了。在我们的服务端项目中,同时演示了调用本地的Service
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="1. 测试启动本地服务" android:textSize="25sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:id="@+id/button1" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="startMyService" android:text="启动服务" /> <Button android:id="@+id/button2" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="stopMyService" android:text="停止服务" /> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="2. 测试绑定本地服务" android:textSize="25sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="bindMyService" android:text="绑定服务" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:onClick="unbindMyService" android:text="解绑服务" /> </LinearLayout> </LinearLayout>
处理MainActivity.java
package com.hbk.servicedemo; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.widget.Toast; import com.hbk.servicedemo.local.MyService; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //启动服务 public void startMyService(View v) { Intent intent = new Intent(this, MyService.class); startService(intent); Toast.makeText(this, "start service", 0).show(); } public void stopMyService(View v) { Intent intent = new Intent(this, MyService.class); stopService(intent); Toast.makeText(this, "stop service", 0).show(); } private ServiceConnection conn; //绑定服务 public void bindMyService(View v) { Intent intent = new Intent(this, MyService.class); //创建连接对象 if(conn==null) { conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { Log.e("TAG", "onServiceDisconnected()"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e("TAG", "onServiceConnected()"); } }; //绑定Service bindService(intent, conn, Context.BIND_AUTO_CREATE); Toast.makeText(this, "bind service", 0).show(); } else { Toast.makeText(this, "已经bindservice", 0).show(); } } //解绑服务 public void unbindMyService(View v) { if(conn!=null) { unbindService(conn); conn = null; Toast.makeText(this, "unbind service", 0).show(); } else { Toast.makeText(this, "还没有bindservice", 0).show(); } } //在Activity死亡之前调用 @Override protected void onDestroy() { super.onDestroy(); if(conn!=null) { unbindService(conn); conn = null; } } }
本地Service,主要重点掌握如下API即可
.startService(Intent service)
stopService(Intent name)
bindService(Intent service, ServiceConnection conn, int flags)
unbindService(ServiceConnection conn)
远程Service,先定义AIDL文件,如我们新建IStudentService.aidl(可以新建interface,然后重命名)
IStudentService.aidl,同包下的类也需要import(注意)
package com.hbk.servicedemo.remote; import com.hbk.servicedemo.remote.Student; interface IStudentService { Student getStudentById(int id); }
第二步,实体类需要实现Parcelable接口
Student.java
package com.hbk.servicedemo.remote; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; public class Student implements Parcelable { private int id; private String name; private double price; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", price=" + price + "]"; } public Student(int id, String name, double price) { super(); this.id = id; this.name = name; this.price = price; } public Student() { super(); // TODO Auto-generated constructor stub } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { Log.e("TAG", "打包 writeToParcel()"); dest.writeInt(id); dest.writeString(name); dest.writeDouble(price); } // 添加一个静态成员,名为CREATOR,该对象实现了Parcelable.Creator接口 public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() { @Override public Student createFromParcel(Parcel source) { // id int id = source.readInt(); // name String name = source.readString(); // price double price = source.readDouble(); return new Student(id, name, price); } @Override public Student[] newArray(int size) { return new Student[size]; } }; }
固定模式,public static final Parcelable.Creator<Student> CREATOR,名字一定叫CREATOR,注意序列化的顺序,即打包读写顺序要一致。
第三步,新建Student.aidl文件
package com.hbk.servicedemo.remote; parcelable Student;
清单文件中注册service
<service android:name="com.hbk.servicedemo.local.MyService"/> <service android:name="com.hbk.servicedemo.remote.MyRemoteService"> <intent-filter> <action android:name="com.hbk.servicedemo.remote.MyRemoteService.Action"/> </intent-filter> </service>
定义Action,主要是为了给客户端进行调用
客户端处理Activity
package com.hbk.servicedemoclient; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.Toast; import com.hbk.servicedemo.remote.IStudentService; import com.hbk.servicedemo.remote.Student; public class MainActivity extends Activity { private EditText et_aidl_id; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_aidl_id = (EditText) findViewById(R.id.et_aidl_id); } private ServiceConnection conn; private IStudentService studentService; // 绑定远程服务 public void bindRemoteService(View v){ Intent intent = new Intent("com.hbk.servicedemo.remote.MyRemoteService.Action"); if(conn == null){ conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e("TAG", "onServiceConnected()"); studentService = IStudentService.Stub.asInterface(service); } }; bindService(intent, conn, Context.BIND_AUTO_CREATE); Toast.makeText(this, "绑定Service", 0).show(); } } public void invokeRemote(View v) throws RemoteException { if(studentService!=null) { int id = Integer.parseInt(et_aidl_id.getText().toString()); Student student = studentService.getStudentById(id); Toast.makeText(this, student.toString(), 0).show(); } } public void unbindRemoteService(View v) { if (conn != null) { unbindService(conn); conn = null; studentService = null; Toast.makeText(this, "解绑Service", 0).show(); } else { Toast.makeText(this, "还未绑定Service", 0).show(); } } }
绑定的时候,传入服务端的action
Intent intent = new Intent(“com.hbk.servicedemo.remote.MyRemoteService.Action”);
服务连接的时候,初始化业务服务
@Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e("TAG", "onServiceConnected()"); studentService = IStudentService.Stub.asInterface(service); }
测试