免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2001 | 回复: 1

[Android] Android服务之Service(其二)关于AIDL进程间通信 [复制链接]

论坛徽章:
80
20周年集字徽章-庆
日期:2020-10-28 14:09:1215-16赛季CBA联赛之北京
日期:2020-10-28 13:32:5315-16赛季CBA联赛之北控
日期:2020-10-28 13:32:4815-16赛季CBA联赛之天津
日期:2020-10-28 13:13:35黑曼巴
日期:2020-10-28 12:29:1520周年集字徽章-周	
日期:2020-10-31 15:10:0720周年集字徽章-20	
日期:2020-10-31 15:10:07ChinaUnix元老
日期:2015-09-29 11:56:3020周年集字徽章-年
日期:2020-10-28 14:14:56
发表于 2015-09-28 13:31 |显示全部楼层
一.基础知识
AIDL的作用
    在Android平台,每个应用程序App都运行在自己的进程空间。通常一 个进程不能访问另一个进程的内存空间(一个应用不能访问另一个应用),如果想沟通,需要将对象分解成操作系统可以理解的基本单元,Android提供了AIDL来处理。

    AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参 数。换句比较浅显的话来说,就是我这个App应用的activity,需要调用其他App应用的Service.当然同一App应用的activity 与service也可以在不同进程间,这可以设置Service配置中,android:process=":remote"
AIDL的使用
    官方文档特别提醒我们何时使用AIDL是必要的:只有你允许客户端从不同的应用程序为了进程间的通信而去访问你的service,以及想在你的service处理多线程。(太生硬了,不同进程的组件调用吧。)
那么怎么制作AIDL呢?下面步骤

1:创建.aidl文件。新建立个文件并且以.aidl作为后缀保存,在这个文件中编写接口以及方法,这个我们普通java接口声明是一样的,不同的是要显示import 复杂类型,即便复杂类型对象在同一个包内。Java基本数据类型 (int, long, char, boolean等),String和CharSequence,集合接口类型List和Map,不需要import 。

比如:

package com.dongzi;
interface IStockQuoteService{
  double getPrice(String ticker);
}

2:创建好AIDL文件后,刷新下工程,你会发现在gen包下,对应的包下面出现一个与AIDL文件相同的java文件。如:
  1. /*
  2. * This file is auto-generated.  DO NOT MODIFY.
  3. * Original file: D:\\mywordspace\\MyPhone\\src\\com\\dongzi\\IStockQuoteService.aidl
  4. */
  5. package com.dongzi;

  6. public interface IStockQuoteService extends android.os.IInterface {
  7.     /** Local-side IPC implementation stub class. */
  8.     public static abstract class Stub extends android.os.Binder implements com.dongzi.IStockQuoteService {
  9.         private static final java.lang.String DESCRIPTOR = "com.dongzi.IStockQuoteService";

  10.         /** Construct the stub at attach it to the interface. */
  11.         public Stub() {
  12.             this.attachInterface(this, DESCRIPTOR);
  13.         }

  14.         /**
  15.          * Cast an IBinder object into an com.dongzi.IStockQuoteService
  16.          * interface, generating a proxy if needed.
  17.          */
  18.         public static com.dongzi.IStockQuoteService asInterface(android.os.IBinder obj) {
  19.             if ((obj == null)) {
  20.                 return null;
  21.             }
  22.             android.os.IInterface iin = (android.os.IInterface) obj.queryLocalInterface(DESCRIPTOR);
  23.             if (((iin != null) && (iin instanceof com.dongzi.IStockQuoteService))) {
  24.                 return ((com.dongzi.IStockQuoteService) iin);
  25.             }
  26.             return new com.dongzi.IStockQuoteService.Stub.Proxy(obj);
  27.         }

  28.         public android.os.IBinder asBinder() {
  29.             return this;
  30.         }

  31.         @Override
  32.         public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
  33.                 throws android.os.RemoteException {
  34.             switch (code) {
  35.             case INTERFACE_TRANSACTION: {
  36.                 reply.writeString(DESCRIPTOR);
  37.                 return true;
  38.             }
  39.             case TRANSACTION_getPrice: {
  40.                 data.enforceInterface(DESCRIPTOR);
  41.                 java.lang.String _arg0;
  42.                 _arg0 = data.readString();
  43.                 double _result = this.getPrice(_arg0);
  44.                 reply.writeNoException();
  45.                 reply.writeDouble(_result);
  46.                 return true;
  47.             }
  48.             }
  49.             return super.onTransact(code, data, reply, flags);
  50.         }

  51.         private static class Proxy implements com.dongzi.IStockQuoteService {
  52.             private android.os.IBinder mRemote;

  53.             Proxy(android.os.IBinder remote) {
  54.                 mRemote = remote;
  55.             }

  56.             public android.os.IBinder asBinder() {
  57.                 return mRemote;
  58.             }

  59.             public java.lang.String getInterfaceDescriptor() {
  60.                 return DESCRIPTOR;
  61.             }

  62.             public double getPrice(java.lang.String ticker) throws android.os.RemoteException {
  63.                 android.os.Parcel _data = android.os.Parcel.obtain();
  64.                 android.os.Parcel _reply = android.os.Parcel.obtain();
  65.                 double _result;
  66.                 try {
  67.                     _data.writeInterfaceToken(DESCRIPTOR);
  68.                     _data.writeString(ticker);
  69.                     mRemote.transact(Stub.TRANSACTION_getPrice, _data, _reply, 0);
  70.                     _reply.readException();
  71.                     _result = _reply.readDouble();
  72.                 }
  73.                 finally {
  74.                     _reply.recycle();
  75.                     _data.recycle();
  76.                 }
  77.                 return _result;
  78.             }
  79.         }

  80.         static final int TRANSACTION_getPrice = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
  81.     }

  82.     public double getPrice(java.lang.String ticker) throws android.os.RemoteException;
  83. }
复制代码
AIDL工具自动生成了那么多代码,其实我们只需要知道3个就够了。

public static abstract class Stub extends android.os.Binder implements com.dongzi.IStockQuoteService 静态抽象内部类Stub

private static class Proxy implements com.dongzi.IStockQuoteService         AIDL服务代理类

public double getPrice(java.lang.String ticker) throws android.os.RemoteException;     AIDL公布出的接口,就是我们定义的接口方法

3:把AIDL文件存放在其他客户端应用中,我们这个作为服务端。当然我们也可以方便的把这个应用作为客户端以及服务端。其实根本区别就是为了使调用者与被调用者在不同进程中,于是在服务中添加android:process=":remote"即可。省去了再建立应用客户端调用。

4:AIDL只是请定义一个契约,我们这里需要一个服务来提供服务。于是建立服务MyService.

论坛徽章:
80
20周年集字徽章-庆
日期:2020-10-28 14:09:1215-16赛季CBA联赛之北京
日期:2020-10-28 13:32:5315-16赛季CBA联赛之北控
日期:2020-10-28 13:32:4815-16赛季CBA联赛之天津
日期:2020-10-28 13:13:35黑曼巴
日期:2020-10-28 12:29:1520周年集字徽章-周	
日期:2020-10-31 15:10:0720周年集字徽章-20	
日期:2020-10-31 15:10:07ChinaUnix元老
日期:2015-09-29 11:56:3020周年集字徽章-年
日期:2020-10-28 14:14:56
发表于 2015-09-28 13:33 |显示全部楼层
二.实战
既然我们了解一些基础知识后,现在我们开始来代码吧。假设我们需要在一个进程中调用其他应用的服务,这个服务提供一个股票价格查询,或者GPS定位的服务。

并且定义一个类,继承我们AIDL生成的Stub内部类,并实现我们AIDL定义的方法

代码如下:
  1. package com.dongzi;

  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.IBinder;
  5. import android.os.RemoteException;
  6. import android.util.Log;

  7. public class MyService extends Service {
  8.     static final String TAG="MyService";
  9.    
  10.     //定义内部类MyServiceImpl继承我们的AIDL文件自动生成的内部类,
  11.     //并且实现我们AIDL文件定义的接口方法
  12.     private class MyServiceImpl extends IStockQuoteService.Stub{

  13.         @Override
  14.         public double getPrice(String ticker) throws RemoteException {
  15.             Log.e(TAG, "getPrice");
  16.             return 10.5;
  17.         }
  18.         
  19.     }
  20.    
  21.     @Override
  22.     public IBinder onBind(Intent arg0) {
  23.         //返回AIDL实现
  24.         return new MyServiceImpl();
  25.     }
  26.       
  27.    
  28.     @Override
  29.     public void onDestroy(){
  30.         Log.e(TAG, "Release MyService");
  31.         super.onDestroy();
  32.     }
  33. }
复制代码
我们需要在onBind方法中返回我们的AIDL接口实现对象,以便其他进程调用。

当然了,现在AIDL,以及Service都定义好了,就需要在mainfest.xml中设置
  1. <service android:name=".MyService"
  2.             android:process=":remote"
  3.             >
  4.             <intent-filter>
  5.                 <action android:name="com.dongzi.IStockQuoteService"/>
  6.             </intent-filter>
  7.         </service>
复制代码
在客户端服务端在同个App中,android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。

那么现在客户端来调用我们的服务了,代码如下:
  1. package com.dongzi;

  2. import android.app.Activity;
  3. import android.content.ComponentName;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.ServiceConnection;
  7. import android.os.Bundle;
  8. import android.os.IBinder;
  9. import android.os.RemoteException;
  10. import android.util.Log;
  11. import android.view.View;
  12. import android.view.View.OnClickListener;
  13. import android.widget.Button;

  14. public class MYyActivity extends Activity {
  15.       static final String TAG="MYyActivity";
  16.        @Override
  17.        public void onCreate(Bundle savedInstanceState){
  18.            super.onCreate(savedInstanceState);
  19.            setContentView(R.layout.main);
  20.            Button btnCall=(Button)findViewById(R.id.btnCall);
  21.            if(btnCall!=null)
  22.                btnCall.setOnClickListener(new OnClickListener(){
  23.                 @Override
  24.                 public void onClick(View v) {
  25.                     //绑定一个服务
  26.                     bindMyService();
  27.                 }
  28.                });
  29.        }
  30.       
  31.        IStockQuoteService iService=null;
  32.        private ServiceConnection  conn=new ServiceConnection(){
  33.         @Override
  34.         public void onServiceConnected(ComponentName name, IBinder service) {
  35.             //返回AIDL接口对象,然后可以调用AIDL方法
  36.             iService=IStockQuoteService.Stub.asInterface(service);
  37.             double value=0.0;
  38.             try {
  39.                   value=iService.getPrice("");
  40.             }
  41.             catch (RemoteException e) {
  42.                 Log.e(TAG,"调用出错!");
  43.                 e.printStackTrace();
  44.             }
  45.             Log.e(TAG, "返回数值为:"+value);
  46.         }
  47.         @Override
  48.         public void onServiceDisconnected(ComponentName name) {
  49.             Log.i(TAG, "释放Service");
  50.         }
  51.        };
  52.       
  53.        private void bindMyService(){
  54.            // Intent intent=new Intent("com.dongzi.IStockQuoteService");
  55.            Intent intent=new Intent(this,MyService.class);
  56.            startService(intent);

  57.            bindService(intent, conn, Context.BIND_AUTO_CREATE);
  58.        }
  59. }
复制代码
在按钮点击时候启动service,然后再绑定这个Service.在连接到服务后,我们会发现,调用AIDL中定义的方法成了,打印如下:
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP