AIDL:Android Interface Definition Language,即Android接口定义语言。

下面将介绍如何构建可由其他进程通过 RPC 使用服务。

与许多其他基于 RPC 的解决方案一样,在Android中,需要使用 IDL来定义将向客户端公开的接口。

在Android中,这个 IDL 称为 AIDL。要构建远程服务,执行以下步骤。

1、编写一个AIDL文件来向客户端定义接口。AIDL 文件使用 java语法,它的扩展名是点 .aidl 使用的包名称与Android项目所使用的包相同。
2、新建一个扩展名是 .aidl的AIDL文件添加到项目的任意包下。Android Eclipse 插件将调用AIDL编译器来从 AIDL 文件生成 Java接口文件。
3、实现一个服务并从 onBind()方法返回所生成的接口。
4、将服务配置添加到 AndroidManifest.xml文件中。
   
在AIDL中定义服务接口
      为了展示远程服务实例,下面编写一个服务。此服务将提供一种方法来获取消息并返回结果。要在Android 中编写远程服务,第一步是在 AID文件中定义服务的接口。
服务的 AIDL 定义:

//This file is TestAidlService.aidl    

package com.rain.service; 

interface TestAidlService {  

boolean getResult(String msg); 

}

ITestAidlService 以字符串的形式接受消息,并以布尔形式返回当前的结果。当创建AIDL文件时, Android Eclipse插件将运行 AIDL 编译器来处理 AIDL文件(在构建过程中)。如果AIDL文件成功编译,编译器将生成一个适合 RPC 通信的 Java接口。

请注意,生成的文件将位于在 AIDL文件中相应的包中,在本例中为com.rain.service。

ITestAidlService 接口生成同名的Java文件ITestAidlService.java。生成的文件将放在Eclipse的 gen文件夹中。
 

对于所生成的类,请注意以下几点。

1、在 AIDL 文件中定义的接口在生成的代码中实现为接口 (也就是说,有一个名为ITestAidlService的接口)。

2、名为Stub的 static final 抽象类扩展了 android.os.Binder并实现了 ITestAidlService 。请注意该类是一个抽象类。
3、名为 Proxy的内部类实现了 ITestAidlService , 后者是Stub类的代理。
4、AIDL文件必须位于应该包含所生成文件的包中(在AIDL文件的包声明中指定)。
    
在服务类中实现AIDL接口
      上边我们为服务定义了 AIDL 文件并生成了绑定文件。现在我们将提供该服务的实现。要实现服务的接口,需要编写一个类来扩展 android.app.Service 并实现 TestAidlService 接口。我们将编写的类命名为 TestAidlService 。为了将服务向客户端公开,TestAidlService 需要提供onBind()方法 的实现,我们还需要将一些配置信息添加到 AndroidManifest.xml文件中。  下面给出我们服务类得实现。
TestAidlService 服务实现:

package com.rain.service; 
 
import android.app.Service; 
import android.content.Intent; 
import android.os.IBinder; 
import android.os.RemoteException; 
import android.util.Log; 
 
public class TestAidlService extends Service { 
    private static final String TAG = "TestAidlService"; 
 
    public class TestAidlServiceImpl extends ITestAidlService .Stub { 
 
        @Override 
        public boolean getResult(String msg) throws RemoteException { 
            Log.d(TAG, "getResult() called for " + msg); 
            return true; 
        } 
    } 
 
    @Override 
    public void onCreate() { 
        super.onCreate(); 
        Log.d(TAG, "onCreate called"); 
    } 
 
    @Override 
    public void onDestroy() { 
        super.onDestroy(); 
        Log.d(TAG, "onDestory() called"); 
    } 
 
    @Override 
    public void onStart(Intent intent, int startId) { 
        super.onStart(intent, startId); 
        Log.d(TAG, "onStart() called"); 
    } 
 
    @Override 
    public IBinder onBind(Intent intent) { 
        Log.d(TAG, "onBind() called"); 
        return new TestAidlServiceImpl(); 
    } 
 

      在这个服务类中大家可以看到我们实现了 onBind() 方法。从AIDL文件生成的 Stub类是抽象类并且它实现了 TestAidlService 接口。在我们的服务实现中,有一个扩展了 Stub类得内部类,名为 TestAidlServiceImpl。此类充当着远程服务实现,而且 onBind()方法会返回此类的实例。到此,我们有了一个有效的 ADIL服务,但是外部的客户端还无法连接到它。
      要将服务向客户端公开,需要在AndroidManifest.xml文件中添加服务声明,而这一次我们需要一个Intent 过滤器来公开服务。

 

从客户端应用程序调用服务

      当客户端与服务通信时,它们之间必须有一个协议或契约。在Android中,这个契约就是AIDL。所以,使用服务的第一步是,获取服务的 AIDL文件并将其复制到客户端项目中。当将AIDL文件复制到客户端项目时,AIDL 编译器将创建一个接口定义文件,这个文件与我们在服务端定义的文件相同。这会向客户端公开所有的方法、参数并返回服务的类型。我们创建一个新项目并复制AIDL文件。
    (1)创建一个新的Android项目, 将其命名为 TestAidlClient。使用不同的包名称比如 com.rain.client。在Create Activity字段中使用 MainActivity注意不要把ITestAidlService.aidl文件放到这包中,这个包只有一个MainActivity 类。
    (2)在此项目中新建一个包 com.rain.service,放在src目录下。
    (3)将ITestAidlService.aidl文件从 ITestAidlService项目也就是我们服务端得项目复制到新建的包中。复制过来之后,AIDL编译器会自动生成关联的java文件。

     重新生成的服务接口充当着客户端与服务之间的契约。下一步是获取服务的引用,以便调用getResult()方法。对于远程服务,必须调用 bindService()方法,而不是 startService()方法。


客户端布局文件
<?xml version="1.0" encoding="utf-8"?> 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
    android:id="@+id/bindBtn" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="Bind"/> 
 
    android:id="@+id/callBtn" 
    android:layout_height="wrap_content" 
    android:layout_width="wrap_content" 
    android:text="Call Again"/> 
 
    android:id="@+id/unbindBtn" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="UnBind"/> 
 

MainActivity类

package com.rain.client; 
 
import com.rain.service.ITestAidlService; 
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.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.Toast; 
 
public class MainActivity extends Activity { 
    protected static final String TAG = "ITestAidlClient"; 
    private ITestAidlService testAidlService = null; 
 
    private Button bindBtn; 
    private Button callBtn; 
    private Button unbindBtn; 
 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        bindBtn = (Button) findViewById(R.id.bindBtn); 
        bindBtn.setOnClickListener(new OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                bindService(); 
                bindBtn.setEnabled(false); 
                callBtn.setEnabled(true); 
                unbindBtn.setEnabled(true); 
            } 
        }); 
 
        callBtn = (Button) findViewById(R.id.callBtn); 
        callBtn.setOnClickListener(new OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                callService(); 
            } 
        }); 
        callBtn.setEnabled(false); 
 
        unbindBtn = (Button) findViewById(R.id.unbindBtn); 
        unbindBtn.setOnClickListener(new OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                unbindService(serConn); 
                bindBtn.setEnabled(true); 
                callBtn.setEnabled(false); 
                unbindBtn.setEnabled(false); 
            } 
        }); 
    } 

 

    private void bindService(){

            try{

                    bindService(new Intent(ITestAidlService.class.getName()),  serConn, Context.BIND_AUTO_CREATE); 

            }catch(Exception e)

    }    

//Binder died后回调

    IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient(){

        @Override

        public void binderDied() {

            testAidlService.asBinder().unlinkToDeath(deathRecipient,0);

            testAidlService = null;

            bindService();
        }
    };

    private void callService() { 

        try { 

            boolean isTure =testAidlService .getResult("Are you ok ?"); 

            Toast.makeText(this, "Value from service is " +isTure 
                    Toast.LENGTH_LONG).show(); 
        } catch (RemoteException e) { 
            Log.e("MainActivity", e.getMessage(), e); 
        } 
    } 
 
    private ServiceConnection serConn = new ServiceConnection() { 
        // 此方法在系统建立服务连接时调用  
        @Override 
        public void onServiceConnected(ComponentName name, IBinder service) { 
            Log.v(TAG, "onServiceConnected() called"); 

            testAidlService =ITestAidlService.Stub.asInterface(service); 

            if(testAidlService != null){

                        service.linkToDeath(deathRecipient,0);    

                        callService(); 

                }

        } 
 
        // 此方法在销毁服务连接时调用  
        @Override 
        public void onServiceDisconnected(ComponentName name) { 
            Log.v(TAG, "onServiceDisconnected()"); 
            testAidlService = null; 
        } 
    }; 


MainActivity里边我们定义了三个按钮 分别是 Bind、Call 和 UnBind。当用户单击 Bind 按钮时,活动调用bindService()方法。类似地,当用户点击 UnBind 时,活动调用unbindService()方法。请注意传递给 bindService()方法 的3个参数:AIDL 服务的名称、ServiceConnection 实例和自动创建服务的标志。
    

对于AIDL 服务,需要提供ServiceConnection接口的实现。

此接口定义了两个方法:一个供系统建立服务连接时调用,另一个在销毁服务连接时调用。


        另外,特别需要注意 AIDL服务只支持有限的数据类型,因此,如果用AIDL服务传递一些复杂的数据就需要做更一步处理。

AIDL服务支持的数据类型如下:

       1、Java的简单类型(int、char、boolean等)。不需 要导入(import)。

       2、String和CharSequence。不需要导入 (import)。

       3、List和Map。但要注意,List和Map对象的元素类型必须 是AIDL服务支持的数据类型。不需要导入(import)。

       4、AIDL自动生成的接口。需要导入(import)。

       5、实现android.os.Parcelable接口的类。需要导 入(import)。

其中后两种数据类型需要使用import进行导入,传递不需要import的数据类型的值的方式相同。

传递一个需要 import的数据类型的值(例如,实现android.os.Parcelable接口的类)的步骤略显复杂。

除了要建立一个实现android.os.Parcelable接口的类外,还需要为这个类单独建立一个aidl文件,并使用parcelable关键字进行定义。

否则在编译时就会报错提示:couldn't find import for class xxx ... 。

      最后总结一下android中 本地服务和 AIDL服务的区别。

     本地服务不支持onBind(),它从onBind()返回null,这种类型的服务只能由承载服务的应用程序组件访问。可以调用startService()来调用本地服务。

AIDL服务可以同时供 同一进程内的组件和其他应用程序的组件使用。这种类型的服务在AIDL 文件中为自身与其客户端定义一个契约。服务实现 AIDL契约,而客户端绑定到 AIDL定义。服务通过从 onBind()方法 返回AIDL接口的实现,来实现契约。客户端通过调用 bindService()来绑定到AIDL服务,并调用 unBindService()来从服务断开。

本文链接:http://blog.csdn.net/lechengyuyuan/article/details/13773637  

更多相关文章

  1. [置顶] Android中对Log日志文件的分析
  2. 分享自己在项目中对android文件系统的一些认识
  3. android对html支持接口总结
  4. Android 匿名共享内存Java接口分析
  5. 无废话Android之android下junit测试框架配置、保存文件到手机内
  6. Android动态加载外部jar包及jar包中图片等资源文件
  7. 关于Android初级逻辑思考(续)——android文件夹讲解
  8. Android入门:使用Android自带媒体库读取MP3文件
  9. Android Studio 文件类型图标

随机推荐

  1. Android使用Linux命令执行文件操作
  2. android studio使用.gitignore建立项目过
  3. Android弹出多选框下拉框的实例
  4. mt6735平台wifi漫游阈值
  5. android aidl使用小例子
  6. 【代码】利用Android的Log 演示一个activ
  7. Android沉浸式状态栏三种方式的实现
  8. android 監聽系統屬性變化的方法
  9. Android(安卓)跳转应用市场的应用详情页
  10. Android(安卓)密度转换多分辨率