Android基本功:跨进程调用Services(AIDL Service)
Android基本功:跨进程调用Services(AIDL Service)
一、AIDL Service简介
Android系统中,各个应用都运行在自己的进程中,进程之间一般无法直接进行通信,为了实现进程通信(interprocess communication,简称IPC),Android提供了AIDL Service;
二、与本地Service不同
-
本地Service:直接把IBinder对象本身传递给客户端的ServiceConnection的onServiceConnected方法的第二个参数;
-
远程Service:只将IBinder对象的代理传给客户端的ServiceConnection的onServiceConnected方法的第二个参数;
三、AIDL文件
Android需要AIDL(Android Interface Definition Language)来定义远程接口,这种接口定义语言并不是一种真正的变成语言,只是定义两个进程之间的通信接口;
与Java接口相似,但是存在如下几点差异:
-
AIDL定义接口的源代码必须以.aidl结尾;
-
AIDL用到的数据类型,除了基本类型、String、List、Map、CharSequence之外,其它类型全部都需要导包,即使它们在同一个包中也需要导包;
四、使用AIDL的步骤(详细代码可见AIDLService和AIDLClient项目)
1.创建AIDL文件
package com.example.aidlservice; interface ICat { String getColor(); double getWeight(); }
定义好AIDL文件后,ADT工具会自动在gen/com/example/aidlservice/目录下生成一个ICat.java接口,该类内部包含一个Stub内部类,实现了IBinder,ICat两个接口,这个Stub类会作为远程Service回调类;2.将接口暴露给客户端
package com.example.aidlservice; import java.util.Timer; import java.util.TimerTask; import com.example.aidlservice.ICat.Stub; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class AidlService extends Service { String[] colors = new String[] { "红色", "黄色", "黑色" }; double[] weights = new double[] { 2.3, 3.1, 1.58 }; private String color; private double weight; private CatBinder catBinder; Timer timer = new Timer(); @Override public void onCreate() { super.onCreate(); catBinder = new CatBinder(); timer.schedule(new TimerTask() { @Override public void run() { // 随机地改变service组件内的color,weight属性的值 int rand = (int) (Math.random() * 3); color = colors[rand]; weight = weights[rand]; System.out.println("---------" + rand); } }, 0, 800)}; @Override public IBinder onBind(Intent arg0) { /** * 返回CatBinder对象,在绑定本地Service情况下, * 该catBinder会直接传给客户端的ServiceConnected对象的ServiceConnected * ()方法的第二个参数;在绑定远程Service的情况下 * ,只将catBinder对象的代理传给客户端的ServiceConnected对象的ServiceConnected()方法的第二个参数 */ return catBinder; } @Override public void onDestroy() { timer.cancel(); } /** * 继承Stub,也就是实现了ICat接口,并实现了IBinder接口 * * @author pengcx * */ public class CatBinder extends Stub { @Override public String getColor() throws RemoteException { return color; } @Override public double getWeight() throws RemoteException { return weight; } } }
在AndroidManifext.xml文件中配置该Service;
3.客户端访问AIDLService
将Service端的AIDL文件复制到客户端中,注意要在相同的包名下。
package com.example.aidlclient; import com.example.aidlservice.ICat; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.app.Activity; import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; public class AidlClient extends Activity { private ICat catService; private Button getButton; private EditText colorEditText, weightEditText; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { catService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { // 获取远程Service的onBinder方法返回的对象代理 catService = ICat.Stub.asInterface(service); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_aidl_client); getButton = (Button) findViewById(R.id.getbutton); colorEditText = (EditText) findViewById(R.id.coloredittext); weightEditText = (EditText) findViewById(R.id.weightedittext); // 创建所需要绑定的Service的Intent Intent intent = new Intent(); intent.setAction("org.crazyit.aidl.action.AIDL_SERVICE"); // 绑定远程的服务 bindService(intent, conn, Service.BIND_AUTO_CREATE); getButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 获取并显示远程service的状态 try { colorEditText.setText(catService.getColor()); weightEditText.setText(catService.getWeight() + ""); } catch (RemoteException e) { e.printStackTrace(); } } }); } @Override protected void onDestroy() { super.onDestroy(); // 解除绑定 this.unbindService(conn); } }
错误:java.lang.SecurityException: Binder invocation to an incorrect interface。在使用上请注意,服务端与客户端都要有相同的接口(使用到的),这里的“相同”是指完全相同,包括包名,也就是说要在不同工程下建立相同的包名。
-
用户评论