Android service通过aidl 回调客户端 daemon

前端时间项目运用到AIDL,关于AIDL客户端以及AIDL服务端网络上没有一个比较完备的Demo.

而参考Demo无疑是一个比较快速的学习方法.因此,我写了一个Demo.

供大家参考,也非常欢迎大家对其中写的不好的地方进行指正.

好了,首先简述下基本功能:

在AIDL 客户端三个EditText中输入三个值,点击提交按钮,将这三个值传入到AIDL服务端进行处理.

服务端处理后会执行客户端的回调函数:在AIDL客户端界面进行刷新,并显示一个toast.

接下来看看代码结构:

需要注意的是,两个工程中com.harlan.demo.aidl包内部的文件必须保持一致.

(1)HarlanInfo.java:这是包中唯一的一个java文件,是一个数据结构,该类实现了Parcelable接口

[java] view plaincopyprint?

  1. package com.harlan.demo.aidl;
  2. import android.os.Parcel;
  3. import android.os.Parcelable;
  4. /**
  5. *
  6. * <一句话功能简述>
  7. * Parcelable是Android特有的功能,效率比实现Serializable接口高
  8. *
  9. * @author  Administrator
  10. * @version  [版本号, 2012-12-10]
  11. * @see  [相关类/方法]
  12. * @since  [产品/模块版本]
  13. */
  14. public class HarlanInfo implements Parcelable
  15. {
  16. private String name;
  17. private int age;
  18. private String place;
  19. public String getName()
  20. {
  21. return name;
  22. }
  23. public void setName(String name)
  24. {
  25. this.name = name;
  26. }
  27. public int getAge()
  28. {
  29. return age;
  30. }
  31. public void setAge(int age)
  32. {
  33. this.age = age;
  34. }
  35. public String getPlace()
  36. {
  37. return place;
  38. }
  39. public void setPlace(String place)
  40. {
  41. this.place = place;
  42. }
  43. /**
  44. * <默认构造函数>
  45. */
  46. public HarlanInfo()
  47. {
  48. }
  49. /**
  50. * <默认构造函数>
  51. */
  52. public HarlanInfo(Parcel in)
  53. {
  54. //注意顺序
  55. name = in.readString();
  56. age = in.readInt();
  57. place = in.readString();
  58. }
  59. /**
  60. * seems meaningless
  61. * return 0;
  62. */
  63. @Override
  64. public int describeContents()
  65. {
  66. return 0;
  67. }
  68. /**
  69. * 将对象序列化为一个Parcel对象
  70. *  可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面,
  71. *  再通过createFromParcel从流里读取对象
  72. *  注意:写的顺序和读的顺序必须一致。
  73. */
  74. @Override
  75. public void writeToParcel(Parcel dest, int flags)
  76. {
  77. dest.writeString(name);
  78. dest.writeInt(age);
  79. dest.writeString(place);
  80. }
  81. /**
  82. * 实例化静态内部对象CREATOR实现接口Parcelable.Creator
  83. * public static final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写
  84. */
  85. public static final Parcelable.Creator<HarlanInfo> CREATOR = new Creator<HarlanInfo>(){
  86. //将Parcel对象反序列化为HarlanInfo
  87. @Override
  88. public HarlanInfo createFromParcel(Parcel source)
  89. {
  90. HarlanInfo hlInfo = new HarlanInfo(source);
  91. return hlInfo;
  92. }
  93. @Override
  94. public HarlanInfo[] newArray(int size)
  95. {
  96. return new HarlanInfo[size];
  97. }
  98. };
  99. }

(2)HarlanInfo.aidl :协同HarlanInfo.java文件"作战",缺一不可.

[java] view plaincopyprint?

  1. package com.harlan.demo.aidl;
  2. parcelable HarlanInfo;

(3)ICallBack.aidl:
这是客户端回调方法的接口,在客户端实现其具体方法,在服务端调用执行.

[java] view plaincopyprint?

  1. package com.harlan.demo.aidl;
  2. interface ICallBack{
  3. /**
  4. *callback of AIDLClient
  5. *handle by server
  6. **/
  7. void handleByServer(String param);
  8. }

(4)ExecuteService.aidl:

这是从服务端获取数据方法的接口,在服务端实现其具体方法,在客户端调用执行.

参数info是由用户输入的数据构成的,同时传递的还要客户端回调方法的句柄,从而服务端可以调用客户端的回调方法.

该方法返回一个HarlanInfo的数据类型,客户端获得此数据,在界面上进行相应的显示.

[java] view plaincopyprint?

  1. package com.harlan.demo.aidl;
  2. import com.harlan.demo.aidl.HarlanInfo;
  3. import com.harlan.demo.aidl.ICallBack;
  4. interface ExecuteServiceAIDL
  5. {
  6. /**
  7. *get info from server and
  8. *Transfer a callback methods handle;
  9. *if occur error ,will be return null
  10. *对于非基本数据类型和String和CharSequence类型,要加上方向指示
  11. *包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
  12. */
  13. HarlanInfo getServerHarlanInfo(in HarlanInfo info,ICallBack icallback);
  14. }

好了,现在对com.harlan.demo.aidl包已经大致了解,build一下project,发现gen文件夹下面多出来一个包:


 包中文件可以随便看看,不看也没事.因为你只要在客户端服务端相应的位置实现对应的接口就可以了.

先来看看服务端,因为服务端相对简单些,不需要界面什么的,只是一个Service.

上代码:

[java] view plaincopyprint?

  1. package com.harlan.demo.service;
  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. import com.harlan.demo.aidl.ExecuteServiceAIDL;
  8. import com.harlan.demo.aidl.HarlanInfo;
  9. import com.harlan.demo.aidl.ICallBack;
  10. public class AIDLService extends Service
  11. {
  12. public static final String TAG = "AIDLService";
  13. private ICallBack mCallBack;
  14. /**
  15. * 绑定服务
  16. */
  17. @Override
  18. public IBinder onBind(Intent intent)
  19. {
  20. // TODO Auto-generated method stub
  21. return mBinder;
  22. }
  23. /**
  24. * 创建服务
  25. */
  26. @Override
  27. public void onCreate()
  28. {
  29. super.onCreate();
  30. }
  31. /**
  32. * 销毁服务
  33. */
  34. @Override
  35. public void onDestroy()
  36. {
  37. super.onDestroy();
  38. }
  39. /**
  40. * 启动服务
  41. */
  42. @Override
  43. public void onStart(Intent intent, int startId)
  44. {
  45. super.onStart(intent, startId);
  46. }
  47. /**
  48. * 解绑服务
  49. */
  50. @Override
  51. public boolean onUnbind(Intent intent)
  52. {
  53. mCallBack = null;
  54. return super.onUnbind(intent);
  55. }
  56. ExecuteServiceAIDL.Stub mBinder = new ExecuteServiceAIDL.Stub()
  57. {
  58. //这里实现了getServiceHarlanInfo接口
  59. @Override
  60. public HarlanInfo getServerHarlanInfo(HarlanInfo info, ICallBack icallback)
  61. throws RemoteException
  62. {
  63. Log.d(TAG,"getServerHarlanInfo");
  64. mCallBack = icallback;
  65. mCallBack.handleByServer("The msg is from server");
  66. HarlanInfo newInfo = new HarlanInfo();
  67. newInfo.setName(info.getName().toLowerCase());
  68. newInfo.setAge(info.getAge() + 10);
  69. newInfo.setPlace("Home");
  70. return newInfo;
  71. }
  72. };
  73. }

一目了然,服务端主要的功能就是实现了aidl中的getServerHarlanInfo(HarlanInfo info, ICallBack icallback)接口.返回了一个mBinder供客户端调用.

写好了服务,还得在Manifest文件里面配置一下:

[java] view plaincopyprint?

  1. <service
  2. android:name=".AIDLService">
  3. <intent-filter>
  4. <action android:name="com.harlan.demo.aidl.service"/>
  5. </intent-filter>
  6. lt;/service>

服务端写好了,就来客户端的了.客户端主要是一个activity,界面相对简单,如图所示:

界面布局相对简单,就不贴代码了.

下面贴ClientActivity的代码:

[java] view plaincopyprint?

  1. package com.harlan.demo.activity;
  2. import android.app.Activity;
  3. import android.content.ComponentName;
  4. import android.content.Intent;
  5. import android.content.ServiceConnection;
  6. import android.os.Bundle;
  7. import android.os.IBinder;
  8. import android.os.RemoteException;
  9. import android.util.Log;
  10. import android.view.View;
  11. import android.widget.Button;
  12. import android.widget.EditText;
  13. import android.widget.Toast;
  14. import com.harlan.demo.aidl.ExecuteServiceAIDL;
  15. import com.harlan.demo.aidl.HarlanInfo;
  16. import com.harlan.demo.aidl.ICallBack;
  17. public class ClientActivity extends Activity
  18. {
  19. public static final String TAG = "ClientActivity";
  20. private static final String BIND_ACTION = "com.harlan.demo.aidl.service";
  21. private EditText mEditTextName;
  22. private EditText mEditTextAge;
  23. private EditText mEditTextPlace;
  24. private Button mButtonCommit;
  25. private ExecuteServiceAIDL executeService;
  26. @Override
  27. protected void onCreate(Bundle savedInstanceState)
  28. {
  29. super.onCreate(savedInstanceState);
  30. setContentView(R.layout.activity_client);
  31. getView();
  32. //用户点击提交按钮,将数据传至服务端进行处理
  33. mButtonCommit.setOnClickListener(new View.OnClickListener()
  34. {
  35. @Override
  36. public void onClick(View v)
  37. {
  38. //绑定服务
  39. getServiceConnect();
  40. }
  41. });
  42. }
  43. private void getView()
  44. {
  45. mEditTextName = (EditText)findViewById(R.id.editText_name);
  46. mEditTextAge = (EditText)findViewById(R.id.editText_age);
  47. mEditTextPlace = (EditText)findViewById(R.id.editText_place);
  48. mButtonCommit = (Button)findViewById(R.id.button_commit);
  49. }
  50. private void getServiceConnect()
  51. {
  52. Intent it = new Intent();
  53. it.setAction(BIND_ACTION);
  54. startService(it);
  55. bindService(it, mserviceConnection, BIND_AUTO_CREATE);
  56. }
  57. ServiceConnection mserviceConnection = new ServiceConnection()
  58. {
  59. @Override
  60. public void onServiceDisconnected(ComponentName name)
  61. {
  62. Log.d(TAG, "onServiceDisconnected");
  63. }
  64. @Override
  65. public void onServiceConnected(ComponentName name, IBinder service)
  66. {
  67. Log.d(TAG, "onServiceConnected");
  68. //获取服务端传过来的IBinder对象,通过该对象调用服务端的方法
  69. executeService = ExecuteServiceAIDL.Stub.asInterface(service);
  70. if (executeService != null)
  71. {
  72. handlerInfo();
  73. }
  74. }
  75. };
  76. private void handlerInfo()
  77. {
  78. String mName;
  79. int mAge;
  80. String mPlace;
  81. if (mEditTextName.getText().toString().equals(""))
  82. {
  83. mEditTextName.setText("Harlan");
  84. mName = "Harlan";
  85. }
  86. else
  87. {
  88. mName = mEditTextName.getText().toString();
  89. }
  90. if (mEditTextAge.getText().toString().equals(""))
  91. {
  92. mAge = 22;
  93. }
  94. else
  95. {
  96. mAge = Integer.parseInt(mEditTextAge.getText().toString());
  97. }
  98. if (mEditTextPlace.getText().toString().equals(""))
  99. {
  100. mPlace = "Nanjing";
  101. }
  102. else
  103. {
  104. mPlace = mEditTextPlace.getText().toString();
  105. }
  106. HarlanInfo mInfo = new HarlanInfo();
  107. mInfo.setName(mName);
  108. mInfo.setAge(mAge);
  109. mInfo.setPlace(mPlace);
  110. try
  111. {
  112. HarlanInfo serverInfo = new HarlanInfo();
  113. //调用服务端的方法
  114. serverInfo = executeService.getServerHarlanInfo(mInfo, mCallBack);
  115. //更新界面
  116. mEditTextName.setText(serverInfo.getName());
  117. mEditTextAge.setText(String.valueOf(serverInfo.getAge()));
  118. mEditTextPlace.setText(serverInfo.getPlace());
  119. unbindService(mserviceConnection);
  120. }
  121. catch (RemoteException e)
  122. {
  123. e.printStackTrace();
  124. }
  125. }
  126. ICallBack.Stub mCallBack = new ICallBack.Stub()
  127. {
  128. //客户端回调方法的具体实现
  129. @Override
  130. public void handleByServer(String param)
  131. throws RemoteException
  132. {
  133. Toast.makeText(getApplicationContext(), param, Toast.LENGTH_LONG).show();
  134. }
  135. };
  136. }

服务端调用客户端回调方法,在界面上显示一个toast.客户端根据服务端传回来的数据,刷新界面.

最后运行结果如图所示:

具体的Demo已经上传至CSDN,下载地址:http://download.csdn.net/detail/singleton1900/4928804

时间: 2024-10-10 13:48:45

Android service通过aidl 回调客户端 daemon的相关文章

Android service binder aidl 关系

/********************************************************************************** * Android service binder aidl 关系 * 声明: * 最近一直被Android中的service.binder.aidl这三者之间的关系给搞得有点难受, * 于是就自己花了点时间,将他们之间的关系给画出来,这样思维上就清晰多了,也方便 * 和朋友沟通,减少沟通成本. * * 2016-1-10 晴 深圳

Android -- Service绑定解绑和aidl

Service是安卓四大组件之一,先前讲到了Service的生命周期,以及非绑定类型的生命周期的例子,这次来分享一下绑定形式的. 应用组件(客户端)可以调用bindService()绑定到一个service.Android系统之后调用service的onBind()方法,它返回一个用来与service交互的IBinder. 绑定是异步的,bindService()会立即返回,它不会返回IBinder给客户端.要接收IBinder,客户端必须创建一个ServiceConnection的实例并传给b

android学习之remote service 的aidl详解

写在前面的话: 关于remote service中使用aidl来实现跨进程,多线程通信,我是参考了三篇文章,大概把这个弄明白了. (1)android 官方关于aidl的说明文档 docs/guide/components/aidl.html (2)Android学习笔记23服务Service之AIDL和远程服务实现进程通信以及进程间传递自定义类型参数 http://blog.csdn.net/honeybaby201314/article/details/19989455 (3) Androi

Android Service AIDL 远程调用服务 简单音乐播放实例的实现

Android Service是分为两种: 本地服务(Local Service): 同一个apk内被调用 远程服务(Remote Service):被另一个apk调用 远程服务需要借助AIDL来完成. AIDL 是什么 AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码.如果在一个进程中(例如Activi

Android Service学习之AIDL, Parcelable和远程服务

AIDL的作用 由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象.在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界.    通过代码来实现这个数据传输过程是冗长乏味的,Android提供了AIDL工具来处理这项工作. AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可

android 怎样用AIDL Service 传递复杂数据

大家都知道在Android中通过AIDL可以跨进程调用Service中的数据,网上也有很多实例,但是大部分实例都是关于基本数据类型的远程调用,很少讲到复杂数据的调用,今天我用一个例子来演示一下怎样用AIDL Service 传递复杂数据. 我们分2步开始: 第一步:部署我们的服务端,也就是Service端: 1:在Service端我先自定义2个类型:Person和Pet.因为我们需要跨进程传递Person对象和Pet对象,所以Person类和Pet类都必须实现Parcelable接口,并要求在实

Android Service IPC通信之Messenger机制

概述 之前我写过一篇博客介绍Service:Android Service全面解析,里面讲过如何实现Service的跨进程(IPC)通信,主要是通过编写AIDL接口文件来实现的.本篇我们来讲讲Service IPC通信的另外一种方式-Messenger. Messenger,也称为信使,通过它可以在不同的进程间传递message对象,在message中放入我们需要传递的数据你就可以实现跨进程通信和传递数据了.所以说Messenger机制是基于消息的跨进程通信方式. 可以看到,我们可以在客户端发送

关于Android Service真正的完全详解,你需要知道的一切

转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52709857 出自[zejian的博客] ??Service全部内容基本会在本篇涉及到,我们将围绕以下主要知识点进行分析: Service简单概述 Service在清单文件中的声明 Service启动服务实现方式及其详解 Service绑定服务的三种实现方式 关于启动服务与绑定服务间的转换问题 前台服务以及通知发送 服务Service与线程Thread的区别 管理服

Android Service使用详解

Service是Android系统中的四大组件之一,主要有两个应用场景:后台运行和跨进程访问.Service可以在后台执行长时间运行操作而不提供用户界面,除非系统必须回收内存资源,否则系统不会停止或销毁服务.服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行. 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC) 需要注意的是,Service是在主线程里执行操作的,可能会因为执行耗时操作而导致ANR 一.基础知识 Service可以分为以下三种形式