Android进程内通信

来源:互联网 发布:啥软件机票便宜 编辑:程序博客网 时间:2024/06/05 09:52

什么是IPC?
IPC(Inter-Process Communication,进程间通信)
IPC ( Instruction per Clock 及CPU每一时钟周期内所执行的指令多少) IPC代表了一款处理器的设计架构,一旦该处理器设计完成之后,IPC值就不会再改变了。

1、Android进程内通信
Android为了屏蔽进程的概念,利用不同的组件[Activity、Service 或者其它组件]来表示进程之间的通信。
组件间通信的核心机制是Intent ,通过Intent可以开启一个Activity或Service,

Intent包含两部分:action和category(区分性数据)、data(内容性数据)
Intent类型:
1)显示Intent---直接指定消息的目的地,只适合同一进程内的不同组件之间通信new Intent(this,Target.class)
2)隐式Intent---AndroidMainifest.xml中注册,一般用于跨进程通信new Intent(String action)

3)实现Intent简单进程间通信
重点在于隐式Intent:
a、一个<activity>包括:
零个或多个<intent-filter>
它主要是作为匹配的标准,能否匹配成功由<action>、<category>、<data>三个tag共同决定的。
b、一个<intent-filter>包括:
一个或多个 <action>
零个或多个 <category>
指定<activity>的分类特征
例如:
<category android :name="android.intent.category.LAUNCHER" />
--说明该<activity>是该project运行 的第一个界面
<category android:name="android.intent.category.HOME" />
--说明该<activity>可以作为Launcher的,即系统 操作界面
c、零个或一个 <data>
指定携带的数据的类型,使用MIME类型描述方式来描述
例如:<data android:mimeType="video/mpeg" />
video/mpeg表示编码格式为mpeg的视频 ,
也可以使用通配符video/*表示任意格式的视频文件类型;

4)一个Intent对应多种匹配结果的处理说明
一个intent有多个可匹配的处理组件,系统如何处理?
分响应消息的组件类型:
1)如果是service那么这些service都可以启动并处理消息。
2)如果是Activity则会弹出一个对话框让用户进行选择。
5)安全问题----权限permission


2、IPC机制
Android 对进程间通信实现了一套轻量级的IPC机制 --- Binder机制,基于此基础之上提供了整体的封装,从而实现对象代理机制。
A、什么是Binder工作模式?
1)客户端通过某种方式得到服务器端的代理对象。
2)客户端通过调用服务器代理对象的方法向服务器端发送请求。
3)代理对象把用户请求通过Android内核(Linux内核)的Binder驱动发送到服务器进程。
4)服务器进程处理用户请求,并通过Android内核(Linux内核)的Binder驱动返回处理结果给客户端的服务器代理对象。
5)客户端收到服务器端的返回结果。
B、binder机制的组成
1)Binder驱动---/dev/binder 是Android内核的一个字符驱动设备,它是IPC的核心部分。
客户端发送请求最终就是通过它来传递到服务端,而服务端的返回结果也是通过它来传给客户端。内核源码:binder.c
2)Service Manager---服务端有服务的话就得向它注册,而客户端需要向它查询、获得服务。
3)提供服务的Server (Service)
提供服务的Server, 对普通的应用开发来讲,咱们用到的就是Service, 具体的工作Android都帮忙做了封装,所以开发变得很容易。
4)调用对象代理的Client (Activity)
普通的应用开发来讲就是 Activity 通过代理对象去请求调用服务。
注意:这个过程是同步的,所以如果估计这个服务调用很耗时,那么需要考虑启新线程来调用,而不能用UI主线程。
5)代理对象 (底层:BpBinder)
客户端进程通过服务代理BpBinder对象,调用transact函数,该函数作用就是把客户端的请求写入binder设备另一端的Service进程。
从JAVA层面来讲,Android已经为我们封装定义了IBinder接口.

3、AIDL--远程服务
1)在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢? 显然, Java中是不支持跨进程内存共享的。
因此要传递对象, 需要把对象解析成操作系统能够理解的数据格式, 以达到跨界对象访问的目的。在JavaEE中,采用RMI通过序列化传递对象。
在Android中, 则采用AIDL(Android InterfaceDefinition Language:接口定义语言)方式实现。

2)什么是AIDL?
AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC)。
原理:进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象。
由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员来说是透明的。

3)使用AIDL实现进程间通信的步骤:
a、远程服务应用中:
远程服务端,也就是RemoteService应用中,在src下某个包中创建一个处理业务的接口类
[Java] 纯文本查看 复制代码
?
1
2
3
4
5
6
7
8
9
package.cn.itcast.bh.service;
 publicinterface IStudentService{
       publicString query(intno);
           }
 然后,根据后面注意事项中的规则,将接口的代码做一些处理,变成如下:
 package.cn.itcast.bh.service;
 interfaceIStudentService{
        String query(intno);
           }


然后,将相应的接口文件的后缀名改为“ .aidl”.
然后,刷新,则系统会在gen目录下生成一个Java文件,会用到这个Java文件中的类及其内部类。
(注意:如果项目中还有有错误的地方,系统则无法根据AIDL生成Java代码。

远程服务的类文件如下:
其中,(1)部分,是来自于系统根据AIDL生成的Java类的一个内部类,远程服务的onBind方法返回的IBinder对象,必须是该类(IstudentService.Stub)的子类的对象。
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
pcakage cn.itcast.bh.remoteService;
  
import cn.itcast.bh.service.IStudentService;
  
public class StudentRemoteService extendsService{
      privateString[] students = newString[]{"张""郭","李""lihao"};
          privateMyBinder myBinder = newMyBinder();
          @override
          publicIBinder onBind(Intent intent) {
                         returnmyBinder;
                 }
          
        privatefinal class MyBinder extends IStudentService.Stub(1){
                 publicString query(intno) throws RemoteException{
                  
                        returnstudents[no];
                         }
                 }
         }


b、访问者的应用中:
将远程服务端的aidl文件拷贝到访问者的应用中(src目录下),然后,访问者端代码如下:
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
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
import android.view.View;
 importandroid.widget.EditText;
 importandroid.widget.TextView;
 importcn.itcast.bh.service.IStudentService;
  
public class MainActivity extendsActivity{
  
        privateEditText noText;
         privateIStudentService studentService;
         privateTextView showView;
         publicvoid onCreate(Bundle savedInstanceState){
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
         noText = (EditText)findViewById(R.id.no);
         showView = (TextView)findViewById(R.id.showView);
         Intent intent =new Intent("cn.itcast.remoteService");
         this.bindService(intent,newMyConnection(),Context.BIND_AUTO_CREATE);
         }
          
        privatefinal class MyConnection implenments ServiceConnection{
                 @override
                 publicvoid onServiceConnected(ComponentName name, IBinder service){
                         srudentService=IStudentService.Stub.asInterface(service);
                 }
                  
                @override
                 publicvoid onSericeDisconnected(ComponentName name) {
                         studentService =null;
                 }
         }
          
        publicvoid query(View v){
                 try{
                         intno = Integer.parseInt(noText.getText().toString());
                         String name = studentService.query(no);
                         showView.setText(name);
                 }catch(Exception e){
                                 e.printStackTrace();
                                 }
                 }
         }
 }


访问者代码中,访问者端拿到的IBinder对象不能(像访问者与本地服务通信那样)强制类型转换,需要通过如下方法进行类型转换。
binder = StudentService.Stub.asInterface(service);
进程间通信的时候,访问者获得的对象,也并不是远程服务onBind方法中返回的原始的对象,
而是那个对象的代理对象,操作系统在代理中做了协议转换的事情,对开发者是透明的。
进程间通过AIDL通信的注意事项:
AIDL文件的书写规则:
1)接口名和aidl文件名相同。
2)接口和方法前不用加访问权限修饰符public,private,protected等,也不能用final,static。
3)aidl默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence),
使用这些类型时不需要import声明。对于List和Map中的元素类型必须是Aidl支持的类型。
如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口。
4)自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中。
5)在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,以指明参数是输入参数、输出参数还是输入输出参数。
6)Java原始类型默认的标记为in,不能为其它标记。       
0 0
原创粉丝点击