Android Service服务(二)AIDL

来源:互联网 发布:云计算基础知识 编辑:程序博客网 时间:2024/05/19 02:26

    一、AIDL的作用

    由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。

    AIDL(Android Interface Definition Language)是一种IDL语言,用于成可以在Android设备上两个进程之间进行通信(interprocess communication,IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。

    注意:AIDL只支持方法,不能定义静态成员,并且方法也不能有类似public等的修饰符。

    二、AIDL的使用步骤

    1、服务端代码:

     第一步:定义一个*.aidl文件,该文件是符合aidl语言定义规范的接口定义,里面定义了外部应用可以访问的方法。当我们保存该文件的时候,eclipse会自动在gen文件夹下生产一个相应的java接口文件。IPerson.aidl代码如下:

package com.example.server;interface IPerson{void setValue(String name);String getValue();}

     第二步:实现AIDL文件生成的JAVA接口Stub。Person.java实现Stub的代码如下:                                                                      

package com.example.server;import com.example.server.IPerson;import android.os.RemoteException;public class Person extends IPerson.Stub{private String name;@Overridepublic void setValue(String name) throws RemoteException {// TODO Auto-generated method stubthis.name = name;}@Overridepublic String getValue() throws RemoteException {// TODO Auto-generated method stubreturn this.name;}

      第三步:定义一个service,并将其注册到androidManifest.xml文件。示例代码如下:

package com.example.server;import com.example.server.IPerson;import android.app.Service;import android.content.Intent;import android.os.IBinder;public class MyService extends Service{private IPerson.Stub iPerson = new Person();@Overridepublic <span style="font-size:18px;">IBinder</span> onBind(Intent intent) {// TODO Auto-generated method stubreturn iPerson;}}
<service android:name="MyService">            <intent-filter>                <action android:name="com.example.server.MyService"/>            </intent-filter> </service>

         第四步:在本应用中的Activity中为自己定义的Service赋值。在实现了自己的Service时,为了其他应用可以通过bindService来和Service进行交互,我们要实现service中的onBind()方法,并且返回一个继承了Binder的内部类。AIDL要求我们,在这里不能再直接去实现Binder类了,而是去实现AIDL提供给我们的Stub类。实现stub类的同时,AIDL还要求我们同时实现我们在接口定义中的各种服务的具体实现。至此,我们的服务端已经和我们的aidl文件绑定到一起了。


 

package com.example.server;import com.example.server.IPerson;import com.example.server.R;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.app.Activity;import android.app.Service;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Toast;public class MainActivity extends Activity implements OnClickListener{private Button bindButton;private Button unbindButton;private IPerson iPerson;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bindButton = (Button)findViewById(R.id.button1);unbindButton = (Button)findViewById(R.id.button2);bindButton.setOnClickListener(this);unbindButton.setOnClickListener(this);}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.button1:Intent intent = new Intent(MainActivity.this,MyService.class);bindService(intent, conn, Service.BIND_AUTO_CREATE);break;case R.id.button2:unbindService(conn);break;default:break;}}private ServiceConnection conn = new ServiceConnection() {//连接对象@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stub}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubiPerson = IPerson.Stub.asInterface(service);if(iPerson!=null){try {iPerson.setValue("AIDL TEST");Toast.makeText(MainActivity.this, "赋值成功", Toast.LENGTH_LONG).show();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();Toast.makeText(MainActivity.this, "赋值失败", Toast.LENGTH_LONG).show();}}}};}


      2、客户端代码:

        第一步:客户端要想使用该服务,首先要知道我们的服务在aidl文件中到底对外提供了什么服务。所以要将服务端的暴露的接口文件aidl文件拷贝一份到客户端的工程中(注意:aidl文件包的路径和服务端的一定要保持一致,否则会报错,报错见后面分析)。

     第二步:想要和service交互,我们要通过bindService方法,该方法有一个ServiceConnection类型的参数,而主要的代码便是在该接口中实现的。

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn = (Button)findViewById(R.id.button1);btn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubIntent intent = new Intent();intent.setAction("com.example.server.MyService");bindService(intent, conn, Service.BIND_AUTO_CREATE);}});}
private ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stub}@Overridepublic synchronized void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubperson = IPerson.Stub.asInterface(service);if(person != null){try {String name1 = person.getValue();Toast.makeText(MainActivity.this, "远程调用成功,值为:"+name1, Toast.LENGTH_LONG).show();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();Toast.makeText(MainActivity.this, "远程调用失败", Toast.LENGTH_LONG).show();}}}};

        三、报错的情况:java.lang.SecurityException: Binder invocation to an incorrect interface
      在使用AIDL远程服务时,经常会遇到上面的报错。发生这样的报错,最主要的原因是上面要注意的地方。也就是客户端的*.aidl文件的包路径与服务器端的包路径不一致导致的。

 

完整工程代码:http://download.csdn.net/detail/yegucheng2618/7802357

参考文章  http://blog.csdn.net/macdroid/article/details/8448742

                        http://blog.csdn.net/myxmu/article/details/7921521

 

0 0
原创粉丝点击