关闭

彻底明白Android中AIDL及其使用

314人阅读 评论(0) 收藏 举报
分类:

1、为什么要有AIDL?

无论学什么东西,最先得弄明白为什么要有这个东西,不要说存在即是合理,存在肯定合理,但是你还是没有明白。对于AIDL有一些人的浅显概念就是,AIDL可以跨进程访问其他应用程序,和其他应用程序通讯,那我告诉你,很多技术都可以访问,如广播(应用A在AndroidManifest.xml中注册指定Action的广播)应用B发送指定Action的广播,A就能收到信息,这样也能看成不同应用之间完成了通讯(但是这种通讯是单向的);还如ContentProvider,通过URI接口暴露数据给其他应用访问;但是这种都算不上是应用之间的通讯。可能最让人迷惑的是Android推出来了Messager,它就是完成应用之间的通讯的。那么为什么还要有AIDL呢,官方文档介绍AIDL中有这么一句话:
?
1
Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.
第一句最重要,“只有当你允许来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL”,其他情况下你都可以选择其他方法,如使用Messager,也能跨进程通讯。可见AIDL是处理多线程、多客户端并发访问的。而Messager是单线程处理。还是官方文档说的明白,一句话就可以理解为什么要有AIDL。那么是不是这样的写个AIDL试试。

2、AIDL使用

第一、定义AIDL文件
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// IRemoteService.aidl
package com.example.android;
 
// Declare any non-default types here with import statements
 
/** Example service interface */
interface IRemoteService {
    /** Request the process ID of this service, to do evil things with it. */
    int getPid();
 
    /** Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}
这段代码也是官方文档的。命名为IRemoteService.aidl,放在com.example.android包下(这个可以随意),保存后Android编译器会在gen目录下自动生成IRemoteService.java文件 第二、定义我们的服务,DDService.java,并且需要在AndroidManifest.xml中注册,并添加“duanqing.test.aidl” 的ACTION
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.example.service;
 
import com.example.android.IRemoteService;
 
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;
 
public class DDService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("DDService onCreate........" + "Thread: " + Thread.currentThread().getName());
    }
    @Override
    public IBinder onBind(Intent arg0) {
        System.out.println("DDService onBind");
        return mBinder;
    }
 
    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
        public int getPid(){
            System.out.println("Thread: " + Thread.currentThread().getName());
            System.out.println("DDService getPid ");
            return Process.myPid();
        }
        public void basicTypes(int anInt, long aLong, boolean aBoolean,
            float aFloat, double aDouble, String aString) {
            System.out.println("Thread: " + Thread.currentThread().getName());
            System.out.println("basicTypes aDouble: " + aDouble +" anInt: " + anInt+" aBoolean " + aBoolean+" aString " + aString);
        }
    };
 
}

这样我们的服务端就完成了,把服务端运行到模拟器(或者手机上),等一会可以看一下打印信息,重点看“线程名” 
第三、实现客户端测试代码 新建另一个工程,同样需要添加AIDL协议文件(这是一个标准的协议文件,定义对外服务),这里我列出来我的测试代码:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.example.aidlclient;
 
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.Process;
import android.os.RemoteException;
import android.view.View;
 
import com.example.android.IRemoteService;
 
public class MainActivity extends Activity {
    private IRemoteService remoteService;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
     
    ServiceConnection conn = new ServiceConnection() {
         
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
         
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            remoteService = IRemoteService.Stub.asInterface(service);
            try {
                int pid = remoteService.getPid();
                int currentPid = Process.myPid();
                System.out.println("currentPID: " + currentPid +"  remotePID: " + pid);
                remoteService.basicTypes(12, 1223, true, 12.2f, 12.3, "我们的爱,我明白");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            System.out.println("bind success! " + remoteService.toString());
        }
    };
         
    /**
     * 监听按钮点击
     * @param view
     */
    public void buttonClick(View view) {
        System.out.println("begin bindService");
        Intent intent = new Intent("duanqing.test.aidl");
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
}
4、执行 点击客户端按钮,执行,看打印信息:

看服务端打印,DDService onCreate..........Thread: main,主线程,当客户端调用服务端getPid方法时,服务端是在Thread: Binder2中执行,当客户端调用服务端basicType方法时,服务端是在Thread:Binder1中执行




Android中AIDL的简单使用

2013-03-28 16:31 佚名 oschina 字号:T | T
一键收藏,随时查看,分享好友!

本文通过一个Android中AIDL与service通信的小demo,让刚刚接触这方面的初学者能够对AIDL的简单使用有一个入门级别的的认识。

AD:51CTO 网+ 第十二期沙龙:大话数据之美_如何用数据驱动用户体验

AIDL这里就不加累述它的概念定义等等,免得长篇大幅。下面介绍的是简单的一次使用AIDL成功与service通信的一个例子:

1.在项目包下新建一个IInfo.aidl,并在其中添加你要调用的方法,格式和java中接口一样。package com.android.server;

  1. interface IInfo {  
  2.     boolean start(); 
  3.     void stop(); 
  4.     void locate(int x, int y); 
  5.     void move(int dx, int dy); 
  6.     void getLocation(inout int[] p);//参数为数组的话,可以加上inout,不然会报错 
  7.     void setTimeout(int t); 
  8.     int getTimeout(); 
  9.     void setBitmap(inout byte[] bmp, int width, int height);}   

正确写好之后,eclipse的adt会自动在gen目录下生成一个IInfo.java文件

2.新建一个CursorService.java类,继承IInfo.stub,如下:

  1. package com.android.server; 
  2. public class CursorService extends ICursorInfo.Stub{ 
  3.     final boolean hasService; 
  4.     public CursorService() { 
  5.         hasService = initializeJNI(); 
  6.     } 
  7.     public synchronized boolean start() { 
  8.         if (hasService) 
  9.             return start0(); 
  10.         return false
  11.     } 
  12.     public synchronized void stop() { 
  13.         if (hasService) 
  14.             stop0(); 
  15.     } 
  16.     public synchronized void locate(int x, int y) { 
  17.         if (hasService) 
  18.             locate0(x, y); 
  19.     } 
  20.   
  21.     public synchronized void move(int dx, int dy) { 
  22.        if (hasService) 
  23.            move0(dx, dy); 
  24.     } 
  25.   
  26.     public synchronized void getLocation(int[] p) { 
  27.         if (p == null
  28.             throw new NullPointerException("p is null"); 
  29.         if (p.length < 2
  30.             throw new IllegalArgumentException("p.len must >= 2"); 
  31.         if (hasService) 
  32.             getPosition0(p); 
  33.     } 
  34.     public synchronized void setTimeout(int t) { 
  35.         if (hasService) 
  36.             setTimeout0(t); 
  37.     } 
  38.   
  39.     public synchronized int getTimeout() { 
  40.         if (hasService) 
  41.             return getTimeout0(); 
  42.         return -1
  43.     } 
  44.   
  45.     public void setBitmap(byte[] bmp, int width, int height) { 
  46.         if(bmp == null
  47.             throw new NullPointerException("bmp is null"); 
  48.         if(width < 0 || height < 0
  49.            throw new IllegalArgumentException("width < 0 || height < 0"); 
  50.        if(width * height > bmp.length) 
  51.             throw new IndexOutOfBoundsException("bmp less than width*height"); 
  52.         setBitmap0(bmp,width,height); 
  53.     } 

在其中实现你aAIDL中的方法

3. 新建一个Manager类,在其中构造一个内部服务连接类,实现ServiceConnection接口:

  1. public class Manager { 
  2.     private static final String TAG = "Manager"
  3.     private IInfo   iCurSer; 
  4.     private Manager(){ 
  5.     } 
  6.       
  7.     public Manager(Context ctx){ 
  8.         this.context = ctx; 
  9.         new Manager(); 
  10.     } 
  11.       
  12.        /**这里就可以与service正常通信,调用service中的方法**/ 
  13.     public void startService(){ 
  14.         Intent intent=new Intent("com.android.server.CursorService"); 
  15.         context.bindService(intent,new CursorServiceConnection(), 
  16.                 Service.BIND_AUTO_CREATE); 
  17.     } 
  18.     /** 
  19.      * 实现ServiceConnection接口 
  20.      * */ 
  21.     public final class CursorServiceConnection implements ServiceConnection{ 
  22.        // 和CursorService绑定时系统回调这个方法 
  23.         @Override 
  24.         public void onServiceConnected(ComponentName name, IBinder service) { 
  25.            // 此处不能使用强制转换, 应该调用Stub类的静态方法获得CursorService接口的实例对象 
  26.            iCurSer=ICursorInfo.Stub.asInterface(service); 
  27.         } 
  28.   
  29.         //解除和CursorService的绑定时系统回调这个方法 
  30.         @Override 
  31.         public void onServiceDisconnected(ComponentName name) { 
  32.             iCurSer=null
  33.         } 
  34.     } 

Android中AIDL的简单使用就mark到这吧,希望对刚刚学Android的开发者能有些帮助。


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:50997次
    • 积分:772
    • 等级:
    • 排名:千里之外
    • 原创:21篇
    • 转载:46篇
    • 译文:0篇
    • 评论:5条
    文章分类
    最新评论