Android进程间通信IPC详解

mloi8526 8年前
   <p>最近项目有进程间通信的需求,我使用的是IPC通信的方式,这是Android中很传统的一种进程间通信的方式,在这里分享给大家。</p>    <h2>进程间通信意义</h2>    <p>我们为什么要使用进程间通信。我说一个场景,比如我们有两个App,其中一个App(名字为A),有授权登陆,我们还有一个App(名字为B)可能是A的附属App,或者同期产品,我们希望有相同的账号,也就是A登陆了,B就自动登录了。那么B在进入的时候需要从A中拿登陆信息,比如姓名性别,昵称等。这时候就涉及到进程间通信了。或者B中需要一些加密算法,我们不想在B中暴露,可以把值传给A,然后A计算完再传递回来。</p>    <p>当然还有其它场景,这里不再赘述了。</p>    <h2>建立个工程</h2>    <p>首先我们当然要建立一个工程,最普通的工程就可以。</p>    <h2>服务端App</h2>    <p>这个工程中的第一个module服务端module,也就是上面提到的A app,内容提供的app</p>    <p>我们在src/main中建立一个aidl文件夹:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/fafddf1ee731c9708ab8ab7d4f9e485b.png"></p>    <p>右键点击aidl文件夹,new一个aidl文件:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8e44fe264321203cc9fa8164bef00696.png"></p>    <p>在里面建立一个文件,比如我们想获取用户信息:</p>    <pre>  <code class="language-java">interface IPeople {      /**       * Demonstrates some basic types that you can use as parameters       * and return values in AIDL.       */       String getName();       String getSex();  }</code></pre>    <p>然后rebuild一下工程,这时,会在build文件夹下生成一个文件</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/fb2e831fc3c958d099ee237b4a2118d5.png"></p>    <p>这个文件就是aidl生成的对应的接口文件,没有这个文件,我们之后在引用接口的时候会报错。你不用给它转移地方,放在这就行了。</p>    <p>然后我们写一个服务Service,提供数据:</p>    <pre>  <code class="language-java">public class AidlService extends Service{      private PeopleBinder peopleBinder;      @Override      public void onCreate() {          super.onCreate();              peopleBinder = new  PeopleBinder();      }        @Override      public IBinder onBind(Intent intent) {          return peopleBinder;      }        public class PeopleBinder extends IPeople.Stub      {              @Override          public String getName() throws RemoteException {              return "deep";          }            @Override          public String getSex() throws RemoteException {              return "man";          }      }  }</code></pre>    <p>其中PeopleBinder是进程间传递数据的媒介,如果你想传一个数据类,那么这个数据类一定要序列化。PeopleBinder实现的接口,就是刚才我们生成的那个文件中的接口。所以一定要等aidl接口文件生成我们再去写这个类。</p>    <p>然后将Service注册在AndroidManifest中,注意要加一个action,方便客户端App启动:</p>    <pre>  <code class="language-java"><service android:name=".AidlService">              <intent-filter>                  <action android:name="deep.testaidl.AidlService"/>              </intent-filter>          </service></code></pre>    <p>要注意app要安装到手机上啊,否则后面怎么获取……</p>    <h2>客户端App</h2>    <p>我们新建一个module,这个module就是客户端App,也就是我们上文中提到的B App,内容索取者。</p>    <p>用同样的方式建立一个aidl文件,这个aidl文件要与上面的一样,且路径也要一样,如图所示:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/3b386d1bb9de27a9acaefcb8ef2bb22d.png"></p>    <p>可以看到路径一样,文件名一样,当然内容也一样。</p>    <p>这样才能保证协议一致。然后还是rebuild一下。生成对应的接口文件。</p>    <p>然后我们在Activity中,随便写一个布局(这个不多说了,与本文主旨无关),有个按钮,有个显示就行。</p>    <p>然后开始获取用户资料了,首先,我们需要定义一个协议接口,也就是你获取用户资料的接口:</p>    <pre>  <code class="language-java">private IPeople people;//协议接口</code></pre>    <p>接着需要建立一个服务连接,与服务端App刚写的那个Service进行连接通信:</p>    <pre>  <code class="language-java">private ServiceConnection conn = new ServiceConnection() {          @Override          public void onServiceConnected(ComponentName name, IBinder service) {              people = IPeople.Stub.asInterface(service);//连接建立成功,读取数据              try {                   textView.setText("name ="+people.getName()+" sex="+people.getSex());              } catch (RemoteException e) {                  e.printStackTrace();              }            }            @Override          public void onServiceDisconnected(ComponentName name) {              people = null;            }      };</code></pre>    <p>刚才不是写了一个按钮吗,添加一个点击事件,打开服务端写好的Service,进行通信:</p>    <pre>  <code class="language-java">button.setOnClickListener(new View.OnClickListener() {              @Override              public void onClick(View view) {                  Intent intent = new Intent();                  intent.setAction("deep.testaidl.AidlService");                  intent.setPackage("deep.testaidl");                  bindService(intent,conn, Service.BIND_AUTO_CREATE);              }          });</code></pre>    <p>由于我们刚才在服务连接的回调中,将用户信息设置到了textview上,这样就可以显示出来了。</p>    <p>好了,这样一次通信就完成了,是不是没有想象的复杂。</p>    <h2>总结</h2>    <p>这种进程间通信的方式还是比较传统的,用的也比较多,了解一下对于以后的学习很有帮助,如有其它问题可以关注我的公众号留言给我,我会第一时间回复。</p>    <p> </p>    <p> </p>    <p>来自:https://juejin.im/post/58d39de6a22b9d00644eb60b</p>    <p> </p>