`
janla
  • 浏览: 112979 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

AIDL --- Android中的远程接口

阅读更多
    在Android中, 每个应用程序都可以有自己的进程. 在写UI应用的时候, 经常要用到Service. 在不同的进程中, 怎样传递对象呢?  显然, Java中不允许跨进程内存共享. 因此传递对象, 只能把对象拆分成操作系统能理解的简单形式, 以达到跨界对象访问的目的. 在J2EE中,采用RMI的方式, 可以通过序列化传递对象. 在Android中, 则采用AIDL的方式. 理论上AIDL可以传递Bundle,实际上做起来却比较麻烦.

AIDL(AndRoid接口描述语言)是一种借口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象.

AIDL的IPC的机制和COM或CORBA类似, 是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值. 如果要使用AIDL, 需要完成2件事情: 1. 引入AIDL的相关类.; 2. 调用aidl产生的class.

具体实现步骤如下:

1、创建AIDL文件, 在这个文件里面定义接口, 该接口定义了可供客户端访问的方法和属性。 如: ITaskBinder.adil

package com.cmcc.demo;

 

import com.cmcc.demo.ITaskCallback;

 

interface ITaskBinder {

    

    boolean isTaskRunning();

        

    void stopRunningTask();    

    

    void registerCallback(ITaskCallback cb);    

   

    void unregisterCallback(ITaskCallback cb);

}


其中: ITaskCallback在文件ITaskCallback.aidl中定义:

package com.cmcc.demo;

 

interface ITaskCallback {

    void actionPerformed(int actionId);

}


注意: 理论上, 参数可以传递基本数据类型和String, 还有就是Bundle的派生类, 不过在Eclipse中,目前的ADT不支持Bundle做为参数, 据说用Ant编译可以, 我没做尝试.

2、编译AIDL文件, 用Ant的话, 可能需要手动, 使用Eclipse plugin的话,可以根据adil文件自动生产java文件并编译, 不需要人为介入.

3、在Java文件中, 实现AIDL中定义的接口. 编译器会根据AIDL接口, 产生一个JAVA接口。这个接口有一个名为Stub的内部抽象类,它继承扩展了接口并实现了远程调用需要的几个方法。接下来就需要自己去实现自定义的几个接口了.

ITaskBinder.aidl中接口的实现, 在MyService.java中接口以内嵌类的方式实现:

private final ITaskBinder.Stub mBinder = new ITaskBinder.Stub() {

        public void stopRunningTask() {

            //@TODO

        }

        

        public boolean isTaskRunning() {

            //@TODO

            return false;

        } 

        

        public void registerCallback(ITaskCallback cb) {

            if (cb != null) mCallbacks.register(cb);

        }

        public void unregisterCallback(ITaskCallback cb) {

            if (cb != null) mCallbacks.unregister(cb);

        }

};


在MyActivity.java中ITaskCallback.aidl接口实现:

private ITaskCallback mCallback = new ITaskCallback.Stub() {

        public void actionPerformed(int id) {

           //TODO

            printf("callback id=" + id);

        }

};

4、向客户端提供接口ITaskBinder, 如果写的是service,扩展该Service并重载onBind ()方法来返回一个实现上述接口的类的实例。这个地方返回的mBinder,就是上面通过内嵌了定义的那个. (MyService.java)

    public IBinder onBind(Intent t) {

        printf("service on bind");

        return mBinder;

}


在Activity中, 可以通过Binder定义的接口, 来进行远程调用.

5、在服务器端回调客户端的函数. 前提是当客户端获取的IBinder接口的时候,要去注册回调函数, 只有这样, 服务器端才知道该调用那些函数在:MyService.java中:
    void callback(int val) {

        final int N = mCallbacks.beginBroadcast();

        for (int i=0; i<N; i++) {

            try {

                mCallbacks.getBroadcastItem(i).actionPerformed(val);

            } catch (RemoteException e) {

                // The RemoteCallbackList will take care of removing

                // the dead object for us.

            }

        }

        mCallbacks.finishBroadcast();

}


AIDL的创建方法:

AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。 由于远程调用的需要, 这些参数和返回值并不是任何类型.下面是些AIDL支持的数据类型:

1. 不需要import声明的简单Java编程语言类型(int,boolean等)
2. String, CharSequence不需要特殊声明

3. List, Map和Parcelables类型, 这些类型内所包含的数据成员也只能是简单数据类型, String等其他比支持的类型.
(
(另外: 我没尝试Parcelables, 在Eclipse+ADT下编译不过, 或许以后会有所支持).
下面是AIDL语法:
// 文件名: SomeClass.aidl
// 文件可以有注释, 跟java的一样
// 在package以前的注释, 将会被忽略.
// 函数和变量以前的注释, 都会被加入到生产java代码中.
package com.cmcc.demo;
 // import 引入语句

import com.cmcc.demo.ITaskCallback;

 

interface ITaskBinder {

    //函数跟java一样, 可以有0到多个参数 ,可以有一个返回值

    boolean isTaskRunning();

        

    void stopRunningTask();    

    //参数可以是另外的一个aidl定义的接口

    void registerCallback(ITaskCallback cb);    

   

void unregisterCallback(ITaskCallback cb);

//参数可以是String, 可以用in表入输入类型, out表示输出类型.
int getCustomerList(in String branch, out String[] customerList);

 
} 


实现接口时有几个原则:
.抛出的异常不要返回给调用者. 跨进程抛异常处理是不可取的.
.IPC调用是同步的。如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,你应该避免在Activity的主线程中调用。 也就是IPC调用会挂起应用程序导致界面失去响应. 这种情况应该考虑单起一个线程来处理.
.不能在AIDL接口中声明静态属性。

IPC的调用步骤:
1. 声明一个接口类型的变量,该接口类型在.aidl文件中定义。
2. 实现ServiceConnection。
3. 调用ApplicationContext.bindService(),并在ServiceConnection实现中进行传递.
4. 在ServiceConnection.onServiceConnected()实现中,你会接收一个IBinder实例(被调用的Service). 调用
    YourInterfaceName.Stub.asInterface((IBinder)service)将参数转换为YourInterface类型。
5. 调用接口中定义的方法。 你总要检测到DeadObjectException异常,该异常在连接断开时被抛出。它只会被远程方法抛出。
6. 断开连接,调用接口实例中的ApplicationContext.unbindService()



下面是整个程序:
1. ITaskCallback.aidl

 

package com.cmcc.demo;

 

interface ITaskCallback {

    void actionPerformed(int actionId);

}

 

2. ITaskBinder.aidl

package com.cmcc.demo;

 

import com.cmcc.demo.ITaskCallback;

 

interface ITaskBinder {

    

    boolean isTaskRunning();

        

    void stopRunningTask();    

    

    void registerCallback(ITaskCallback cb);    

   

    void unregisterCallback(ITaskCallback cb);

}

 

3.  MyService.java

package com.cmcc.demo;

 

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.RemoteCallbackList;

import android.os.RemoteException;

import android.util.Log;

 

public class MyService extends Service {

        

    @Override

    public void onCreate() {

        printf("service create");

    }

    

    @Override

    public void onStart(Intent intent, int startId) {

        printf("service start id=" + startId);

        callback(startId);

    }

    

    @Override

    public IBinder onBind(Intent t) {

        printf("service on bind");

        return mBinder;

    }

    

    @Override

    public void onDestroy() {

        printf("service on destroy");

        super.onDestroy();

    }

 

    @Override

    public boolean onUnbind(Intent intent) {

        printf("service on unbind");

        return super.onUnbind(intent);

    }

    

    public void onRebind(Intent intent) {

        printf("service on rebind");

        super.onRebind(intent);

    }

    

    private void printf(String str) {

        Log.e("TAG", "###################------ " + str + "------");

    }

    

    void callback(int val) {

        final int N = mCallbacks.beginBroadcast();

        for (int i=0; i<N; i++) {

            try {

                mCallbacks.getBroadcastItem(i).actionPerformed(val);

            } catch (RemoteException e) {

                // The RemoteCallbackList will take care of removing

                // the dead object for us.

            }

        }

        mCallbacks.finishBroadcast();

    }

    

    private final ITaskBinder.Stub mBinder = new ITaskBinder.Stub() {

        public void stopRunningTask() {

            

        }

        

        public boolean isTaskRunning() {

            return false;

        } 

        

        public void registerCallback(ITaskCallback cb) {

            if (cb != null) mCallbacks.register(cb);

        }

        public void unregisterCallback(ITaskCallback cb) {

            if (cb != null) mCallbacks.unregister(cb);

        }

    };

    

    final RemoteCallbackList<ITaskCallback> mCallbacks

        = new RemoteCallbackList<ITaskCallback>();

}

 

4. MyActivity.java

package com.cmcc.demo;

 

import android.app.Activity;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.ServiceConnection;

import android.graphics.Color;

import android.os.Bundle;

import android.os.IBinder;

import android.os.RemoteException;

import android.util.Log;

import android.view.View;

import android.view.ViewGroup;

import android.view.View.OnClickListener;

import android.widget.AbsoluteLayout;

import android.widget.Button;

import android.widget.LinearLayout;

import android.widget.RelativeLayout;

import android.widget.TextView;

 

import java.io.BufferedReader;

import java.io.File;

import java.io.FileOutputStream;

import java.io.FileReader;

import java.io.PrintWriter;

 

public class MyActivity extends Activity {

    

    private Button btnOk;

    private Button btnCancel;

    

    @Override

    public void onCreate(Bundle icicle) {

        super.onCreate(icicle);

        

        setContentView(R.layout.test_service);

        

        btnOk = (Button)findViewById(R.id.btn_ok);

        btnCancel = (Button)findViewById(R.id.btn_cancel);

        

        btnOk.setText("Start Service");

        btnCancel.setTag("Stop Service");

        

        btnOk.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                onOkClick();

            }

        });

 

        btnCancel.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                onCancelClick();

            }

        }); 

    }

    

    void onOkClick() {

        Bundle args = new Bundle();        

        

        Intent intent = new Intent(this, MyService.class);

        intent.putExtras(args);   

        

        //printf("send intent to start");

        

        //startService(intent);

        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

        startService(intent);

    }

    

    void onCancelClick() {

        Intent intent = new Intent(this, MyService.class);

        //printf("send intent to stop");

        

        unbindService(mConnection);

        //stopService(intent);

    }

    

    private void printf(String str) {

        Log.e("TAG", "###################------ " + str + "------");

    }

    

    ITaskBinder mService;

    

    private ServiceConnection mConnection = new ServiceConnection() {

        public void onServiceConnected(ComponentName className,

                IBinder service) {

            mService = ITaskBinder.Stub.asInterface(service);

            try {

                mService.registerCallback(mCallback);

            } catch (RemoteException e) {

            }

 

        }

        

        public void onServiceDisconnected(ComponentName className) {

            mService = null;

        }

    };

    

    private ITaskCallback mCallback = new ITaskCallback.Stub() {

        public void actionPerformed(int id) {

            printf("callback id=" + id);

        }

    };

}
分享到:
评论
2 楼 abinxue 2011-12-13  
谢谢···对我有帮助
1 楼 carywei 2010-05-12  
IPC讲的很细~~

相关推荐

    AIDL设计远程接口.ppt

    AIDL设计远程接口.ppt,专业介绍AIDL的文档

    Android工作实践总结:Aidl 远程调用(aidl实例总结)

    Android工作实践总结:Aidl 远程调用(aidl实例总结) AIDL的IPC的机制和COM或CORBA类似, 是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值. 如果要使用AIDL, 需要完成2件事情: 1. 引入AIDL的...

    Android远程接口之AIDL——Parcelable、in、out、inout简例

    Android远程接口之AIDL——Parcelable、in、out、inout简例 Parcelable in out inout AIDL例子中体现使用方式 详细介绍: http://blog.csdn.net/yangzhaomuma/article/details/50576017

    Android中如何利用AIDL机制调用远程服务

    在Android中,则采用AIDL(Android Interface DefinitionLanguage:接口描述语言)方式实现。 AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC)。...

    Android RemoteService AIDL 方式实现

    Android 远程服务 RemoteService 通过AIDL方式实现跨应用接口访问

    AIDL示例(Android Interface Definition Language)

    为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface ...

    AIDL最简单的使用步骤

    AIDL:Android Interface Definition Language,即Android接口定义语言。 为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他...

    Android Service的跨进程通信实战&Service/AIDL远程调用过程解析(Android Q)

    Service的跨进程通信实战 ...我们来看如何在Android中实现? PersonServer端实现 PersonServer端是服务的提供者,我们首先需要创建一个Service来提供该服务,并且需要该服务具备跨进程通信的能力,以便Client端进行

    实例讲解Android中的AIDL内部进程通信接口使用

    首先描述下我们想要实现的内容,我们希望在一个应用中通过点击按钮,去操作另一个进程中应用的音乐播放功能。 如图,我们点击“播放”时,系统就会去远程调用我们提供的一...AIDL(android interface definition lan

    android 3个APK见的AIDL 通信

    实现B为一个主程序,A远程调用B,并对外提供给C一个接口,实现对B函数的笤俑

    Android代码-Andromeda简化了Android模块化的本地远程通信

    Andromeda Andromeda provides communication among modules for both local ...Aidl interface and implemention are the only thing developers need do. bindService() and Service definition are not necessa

    HBriqAIDLExample:Android AIDL示例

    源组件: app:AIDL服务部分hbriqaidlclient:AIDL客户端部分hbriqaidl:AIDL接口 建造: 将ANDROID_HOME导出到sdk路径对于调试apk: $ ./gradlew assembleDebug 跑步: 安装生成apk文件到目标例如亚行安装./...

    Android Service

    Android中的sercice分为本地服务和远程服务: ...(需要将代理接口.java扩展名改为.aidl,继承接口的实现类Stub),另外需要将远程服务中的aidl包名和文件拷贝到本地应用程序的工程中。 远程服务调用的Demo见附件。

    Android开发案例驱动教程 配套代码

    3.2 Android中的组件介绍 22 3.3 使用Android SDK帮助 23 3.3.1 Android SDK API文档 23 3.3.2 Android SDK开发指南 24 3.3.3 Android SDK samples 24 3.4 使用DDMS帮助调试程序 26 3.4.1 启动DDMS 26 3.4.2 ...

    Android使用AIDL方式实现播放音乐案例

    ② 在两个module的main文件中分别新建两个aidl文件(接口),里边定义处理音乐的方法 ③ 在两个AIDL文件定义过方法后在任务栏给他们makeproject,编译成Java文件,才能在service和acvitity中使用 interface.Stub需要...

    aidl使用实例

    包括两个工程,一个是定义aild文件的app,即远程app,一个是调用远程接口的app

    android的服务

    这种情况下Service需要以aidl文件的方式提供服务接口,AIDL工具将生成一个相应的java接口,并且在生成的服务接口中包含一个功能调用的stub服务桩类。Service的实现类需要去继承这个 stub服务桩类。Service的onBind...

    精通ANDROID 3(中文版)1/2

    11.2.4 在AIDL中定义服务接口  11.2.5 实现AIDL接口  11.2.6 从客户端应用程序调用服务  11.2.7 向服务传递复杂的类型  11.3 使用服务的真实示例  11.3.1 Google翻译API  11.3.2 使用Google翻译API  ...

    Android 代码分析

    3 Android JAVA AIDL Analysis 15 4 Android JAVA Binder IPC System 20 5 Android Media Scanner Process 27 5.1 JAVA layer initialize 27 5.2 JAVA layer prescan 28 5.3 C++ layer processDirectory 28 5.4 JAVA...

    Android远程服务编写和调用教程

    网上汗牛充栋的文章都是介绍Android远程服务的,一个个将Binder机制、AIDL讲得头头是道,然而没有几个人能够给出清晰的范例说明如何用最快的方法学会编写和调用一个Android远程服务。若你仅仅是想如何编写或者调用...

Global site tag (gtag.js) - Google Analytics