您的位置:首页 > 移动开发 > Android开发

Android AIDL用法解析

2016-02-17 11:49 483 查看
    先说为什么要使用AIDL吧,根据官方文档的说明,“只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL”,其他情况下你都可以选择其他方法,如使用Messager,也能跨进程通讯。可见AIDL是处理多线程、多客户端并发访问的。而Messager是单线程处理。

   AIDL的使用上大体分三个步骤。

      1 定义AIDL接口

      2 服务端实现接口

      3 客户端调用

   下面开始详细介绍这三步。

    一  定义AIDL接口

定义AIDL接口,客户端和服务器端都要定义,并且要在同一包中。

AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。这些参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。

    其中对于Java编程语言的基本数据类型 (int, long, char, boolean等),String和CharSequence,集合接口类型List和Map,不需要import 语句。
    而如果需要在AIDL中使用其他AIDL接口类型,需要import,即使是在相同包结构下。AIDL允许传递实现Parcelable接口的类,需要import.

    需要特别注意的是,对于非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
    AIDL只支持接口方法,不能公开static变量。

例如 (IMyService.aidl): 

package com.demo;

import com.demo.Person;

interface IMyService {

        void savePersonInfo(in Person person);

        List<Person> getAllPerson();

}

         二   服务端实现接口

    这是一个继承service的类实现上述AIDL接口,这个类中对AIDL的接口进行赋予实际意义

    创建一个类实现刚才那个aidl的接口:

public class RemoteServiceextends Service {

        private LinkedList<Person> personList =new LinkedList<Person>();

        

        @Override

        public IBinder onBind(Intent intent) {

                return mBinder;

        }

        privatefinal IMyService.Stub mBinder =
new IMyService.Stub(){

                @Override

                public
void savePersonInfo(Person person) throws RemoteException {

                        if (person !=
null){

                                personList.add(person);

                        }

                }

                @Override

                public List<Person> getAllPerson()throws RemoteException {

                        return personList;

                }

        };

}

 
  这里会看到有一个名为IMyService.Stub类,这个类是继承Binder的,这里是为OnBInd方法中的返回值服务。

对于实现AIDL接口,官方还提醒我们:

    1. 调用者是不能保证在主线程执行的,所以从一调用的开始就需要考虑多线程处理,以及确保线程安全;
    2. IPC调用是同步的。如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,你应该避免在Activity的主线程中调用。也就是IPC调用会挂起应用程序导致界面失去响应,这种情况应该考虑单独开启一个线程来处理。

    3. 抛出的异常是不能返回给调用者(跨进程抛异常处理是不可取的)。

    三    客户端调用

    客户端访问服务,需要一个SericeConnection和进行绑定服务来完成。

    客户端如何获取AIDL接口呢?通过IMyService.Stub.asInterface(service)来得到IMyService对象:

private IMyService mRemoteService;

private ServiceConnection mRemoteConnection =
new ServiceConnection() {    

        public void onServiceConnected(ComponentName className, IBinder service) {    

                mRemoteService = IMyService.Stub.asInterface(service);    

        }    

        public void onServiceDisconnected(ComponentName className) {    

                mRemoteService = null;    

        }    

};

而service的绑定没有什么不同:

if (mIsRemoteBound) {

        unbindService(mRemoteConnection);

}else{

        bindService(new Intent("com.demo.IMyService"),

                               mRemoteConnection, Context.BIND_AUTO_CREATE);

}

mIsRemoteBound = !mIsRemoteBound;

 Permission权限

    如果Service在AndroidManifest.xml中声明了全局的强制的访问权限,其他引用必须声明权限才能来start,stop或bind这个service.

     另外,service可以通过权限来保护她的IPC方法调用,通过调用checkCallingPermission(String)方法来确保可以执行这个操作。

 AndroidManifest.xml的Service元素

<service
android:name=".RemoteService"
android:process=":remote">

        <intent-filter>

                <actionandroid:name="com.demo.IMyService"/>

        </intent-filter>
</service>

    这里的android:process=":remote",一开始我没有添加的,在同一个程序里使用IPC,即同一个程序作为客户端/服务器端,结果运行mRemoteService = IMyService.Stub.asInterface(service);时提示空指针异常。观察了人家的在不同程序里进行IPC的代码,也是没有这个android:process=":remote"的。后来在官方文档http://androidappdocs.appspot.com/guide/topics/manifest/service-element.html里了解到(留意第二段文字):

android:process
The name of the process where the service is to run. Normally, all components of an application run in the default process created for the application. It has the same name as the application package. The <application> element's process attribute can
set a different default for all components. But component can override the default with its own process attribute, allowing you to spread your application across multiple processes.
 
If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed and the service runs in that process.If the process name begins with a lowercase character,
the service will run in a global process of that name, provided that it has permission to do so. This allows components in different applications to share a process, reducing resource usage.

 也就是说android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android AIDL