Android学习笔记——AIDL跨进程服务的应用

Android 学习笔记
——AIDL:Android Interface Definition Language
今天学习并研究了Andriod接口定义语言。进行如下总结:

基本概念

Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。我们知道4个Android应用程序组件中的3个(Activity、Broadcast和Content Provider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。AIDL则充当在进程间访问远程service的桥梁,编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的。 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象。把.aidl文件保存到工程的src/目录中,在编译应用程序时,SDK工具会在工程的gen/目录中生成IBinder接口文件。生成的文件名与.aidl文件名相匹配,只是使用.java扩展名(例如,IRemoteService.aidl,生成结果是IRemoteService.java)。
创建aidl文件需要注意一下几点:

  1. 方法不需要修饰符(private、public、final等等)。
  2. 以下情况不需要import语句:

    Java编程语言的主要类型 (int, boolean等)

    String

    List -列表中的所有元素必须是在此列出的类型,包括其他AIDL生成的接口和可打包类型。List可以像一般的类(例如List)那样使用,另一边接收的具体类一般是一个ArrayList,这些方法会使用List接口。

    Map - Map中的所有元素必须是在此列出的类型,包括其他AIDL生成的接口和可打包类型。一般的maps(例如Map)不被支持,另一边接收的具体类一般是一个HashMap,这些方法会使用Map接口。

    CharSequence -该类是被TextView和其他控件对象使用的字符序列。

  3. 通常引引用方式传递的其他AIDL生成的接口,必须要import 语句声明

  4. 方法能够带有0或多个参数,并且能够返回一个值或void

以下是aidl文件的编写规范:

具体步骤

1). 创建工程:

Client: package Name:com.taylor.client

Service: package Name:com.taylor.service

Demo功能:Service段提供两个可以返回String的方法。在Client点击Button得到远程service返回的String填写到Client端的TextView中。

2). 编写aidl文件

package com.taylor.aidl;
interface Remote {
       String getValue() ;
    String getName() ;
}

 

如果AIDL文件编写正确。在Eclipse下会自动在gen目录的下生成相同的包以及文件名相同的java文件。如图:

3). 接下来编写Service。实现aidl文件中声明的方法:
文件路径

package com.taylor.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import com.taylor.aidl.Remote;

/**
 * Created by sunhb on 7/9/13.
 */
public class MyService extends Service {

    //声明远程service对象,并实现在aidl中声明的方法:
    private Remote.Stub myAidl = new Remote.Stub() {
        @Override
        public String getValue() throws RemoteException {
            return "AIDL :getValue() ;";
        }

        @Override
        public String getName() throws RemoteException {
            return "AIDL :getName() ;";
        }
    } ;

    @Override
    public IBinder onBind(Intent intent) {
        //在bindService时返回远程service对象:
        return myAidl;
    }

}

 

在编写上面代码时要注意如下两点:

Remote.Stub是根据Remote.aidl文件自动生成的,一般并不需要管这个类的内容,只需要编写一个继承于Remote.Stub类的子类即可。

onBind方法必须返回Remote.Stub类的对象实例,否则客户端无法获得服务对象。
4).在AndroidManif.xml文件中声明service

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.taylor.service"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="14" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.taylor.service.ServiceActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".MyService" android:process=":remote">
            <intent-filter>
                <!-- AIDL完整路径名。必须指明,客户端能够通过AIDL类名查找到它的实现类 -->
                <action android:name="com.taylor.aidl.Remote" />
            </intent-filter>
        </service>
    </application>

</manifest>

 

至此Service端代码完成。

5).以完全相同的方式在Client的相同包名下编写完全相同的AIDL文件。在gen目录中得到java文件。此处不再赘述。如图:

Client端目录结构

6).在Client端完成远程服务的调用:

package com.taylor.client;

import android.app.Activity;
import android.content.ComponentName;
import android.content.DialogInterface;
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.Button;
import android.widget.TextView;
import com.taylor.aidl.Remote;

public class ClientActivity extends Activity implements View.OnClickListener{

    private static final String TAG = "TAG_AIDL" ;

    private TextView show ;
    private Button getValue ,getName ;
    //远程Service对象
    private Remote myAidl ;
    //远程Service连接
    private ServiceConnection connect = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

            //连接建立,通过下面方式实例化远程Service对象
            myAidl = Remote.Stub.asInterface(iBinder) ;
            Log.d(TAG ,"Remote Service Connection...") ;

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

            myAidl = null ;
            Log.d(TAG ,"Remote Service Disconnect...") ;
        }
    } ;
    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        show = (TextView)findViewById(R.id.show) ;
        getValue = (Button) findViewById(R.id.getValue);
        getName = (Button) findViewById(R.id.getName) ;
        getValue.setOnClickListener(this);
        getName.setOnClickListener(this);

        //BindService
        Intent service = new Intent (Remote.class.getName()) ;
        bindService(service ,connect ,BIND_AUTO_CREATE) ;

    }

    @Override
    public void onClick(View view) {
        String str = null ;
        try {
            switch (view.getId()){
                case R.id.getName:
                    str = myAidl.getName() ;
                    Log.d(TAG ,"getName:"+str) ;
                    show.setText(str);
                    break ;
                case R.id.getValue:
                    str = myAidl.getValue() ;
                    show.setText(str);
                    Log.d(TAG ,"getValue:"+str) ;
                    break;
            }

        } catch (RemoteException e) {
            e.printStackTrace();
        } 
    }
}

 

好了,到这里就已经将Demo的功能完成了。试着运行一下:
初始化状态

 

点击“getValue”
getValue

 

点击“getName”
getName

总觉得学习要留下痕迹,知识需要积累,才会从量变转化为质变,当然更希望我的痕迹,能帮助到别人。于是我觉得把我学习的脚步记录下来。这是第一篇。如有遗漏或错误之处欢迎指正。

posted @ 2013-11-11 16:19  Taylor & Code  阅读(301)  评论(0编辑  收藏  举报