Service组件 总结 + 绑定理Service三种实现方式 Messager + Binder + AIDL
在Android中进程按优先级可以分为五类,优先级从高到低排列:
- 前台进程 该进程包含正在与用户进行交互的界面组件,比如一个Activity
- 可视进程 该进程中的组件虽然没有和用户交互,但是仍然可以被看到
- 服务进程 该进程包含在执行后台操作的服务组件,比如播放音乐的进程
- 后台进程 该进程包含的组件没有与用户交互,用户也看不到
- 空进程 没有任何界面组件、服务组件,或触发器组件**
Android系统是进程托管的,也就是说进程都是由系统来管理,系统会按照特定的算来来回收这些进程。在回收中秉承几个原则
1. 尽量延长进程的生命周期,不到必须的情况下不会回收,因为系统回收进程会影响用户体验
2. 按优先级从低到高进行回收
3. 同等优先级的进程越近使用越晚回收。
Activity和Service有什么关系?
这2者一个前台的东西,一个是后台的东西,Activity有界面,生命周期复杂一点,多个onPause和onResume,Activity不展示的时候并不代表就是关闭了,也有可能是onPause的状态。
Servie没有界面,生命周期也比较简单,但Service分前台服务和后台服务,通过setForeground(boolean);来设置,前台服务比后台服务的存活时间会长。设置不得当服务很容易被系统回收掉。
如果你想让这2个东西有关系,那么请重写Service的onBind方法,这里就是把一个Service和一个Activity绑定的,绑定以后Service就会随着Activity关闭而关闭了。如果Service和Activity没有绑定,那么他俩的生命周期就没有关系。
一个常见的应用场景:
loginactivity登陆页面 点击login, 发送给后台的服务类CmdSocketService 去处理登陆业务,
并获取登陆状态(成功失败的反馈)
loginActivity使用封装好的CmdSocketService(service)类的方法:
a) loginActivity类中定义:
CmdSocketService serviceBinder;
// 下面定义用来连接到服务CmdSocketService后的处理函数
private ServiceConnection mConn = newServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder service)
{
// 这里service其实是MyBinder类对象,,其中有个getService()方法,用于返回service对象自己。
// LoginActivity获得了service对象(serviceBinder)的引用,那使用service中方法和普通的类方法一样使用。
serviceBinder=((CmdSocketService.MyBinder)service).getService();
Log.v(TAG,"get CmdSocketService 引用 ok !");
mBound = true;//自己定义的服务是否绑定标记
}
public void onServiceDisconnected(ComponentName className) {
serviceBinder = null;
mBound = false;
}
};
b) onStart()中定义:
Intent intent = new Intent(this,CmdSocketService.class)
bindService(intent, mConn, Context.BIND_AUTO_CREATE);
//===========================================================
service类中的定义:
public class CmdSocketService extends Service{
//1 .
public class MyBinder extends Binder
{
public CmdSocketService getService()
{
Log.v(TAG,"getService()");
return CmdSocketService.this; //返回service对象本身
}
}
// 2.
private MyBinder mBinder = new MyBinder();
//3.反馈给onServiceConnection()
onBind()中实现:
{
return mBinder;
}
activity和services绑定流程:(bindService方式)
1. new intent指定和哪个service绑定
2. 开始绑定,传递服务连接处理函数ServiceConnection()(有点像回调函数),//调用此函数时android会调用service类中的onBind()函数。
3.onBind()函数里面返回了一个Binder子类对象。Binder子类中有个getServices()方法,返回service对象本身。,最终就是为了给loginActiviy返回service对象的引用。
4.logingActivity和service绑定成功后。android会调用onServiceConnected()函数。此函数中IBinder就是service返回的Binder的子类对象MyBinder.
5.调用MyBinder中的方法getService()即可获得service对象的引用。
6.开始调用service中的公共方法吧。
如何启用Service,如何停用Service
Android中的服务和windows中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。服务的开发比较简单,如下:
第一步:继承Service类
public class SMSService extends Service {
}
第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置:
<service android:name=".SMSService" />
服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。
如果打算采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。
服务常用生命周期回调方法如下:
onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,服务也只被创建一次。
onDestroy()该方法在服务被终止时调用。
与采用Context.startService()方法启动服务有关的生命周期方法
onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。
与采用Context.bindService()方法启动服务有关的生命周期方法
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用
采用Context.startService()方法启动服务的代码如下:
public class HelloActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
......
Button button =(Button) this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
Intent intent = new Intent(HelloActivity.this, SMSService.class);
startService(intent);
}});
}
}
采用Context. bindService()方法启动服务的代码如下:
public class HelloActivity extends Activity {
ServiceConnection conn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
}
public void onServiceDisconnected(ComponentName name) {
}
};
@Override public void onCreate(Bundle savedInstanceState) {
Button button =(Button) this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
Intent intent = new Intent(HelloActivity.this, SMSService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
//unbindService(conn);//解除绑定
}});
}
}
绑定Service的三种实现方式之使用Messeager 1
如果你需要在不同进程间通信,你可以在Service中使用Messenger来实现进程中通信。
如果使用这种方式,Service中需要定义一个Handler对象(负责对客户端发送过来的Message进行响应)。
Messenger可以共享给client一个IBinder对象,client通过这个IBinder对象向Service发送Message,而前面提到的Handler对象是这一切的基础。
注:使用这种方式进行通信是不支持多线程的。
那就让我们来看看使用这种方式进行通信吧!
注:Service在声明时必须对外开放,即android:exported="true",且本文是通过Intent启动的Service,所以在声明时该Service可以接收特定的Action。
1、在Service中创建一个Handler对象,来处理从client发过来的Message
2、根据创建的Handler对象创建一个Messenger对象
3、使用Messenger的getBinder方法得到一个IBinder对象,并在Service的onBind方法中将其反出去
4、client在onServiceConnected中根据IBinder参数创建一个Messenger对象(可参考Messenger的构造函数)
5、client可以使用上一步得到的Messenger对象来给Service发送Message了
经过上面的五部我们就能让client与Service进行通信。client使用Messenger对象给Service发送Message后,Service中的Handler将会对消息作出响应。
上面实现的仅仅是单向通信,即client给Service发送消息,如果我需要Service给client发送消息又该怎样做呢?
其实,这也是很容易实现的,下面就让我们接着上面的步骤来实现双向通信吧~
6、在client中创建一个Handler对象,用于处理Service发过来的消息
7、根据client中的Handler对象创建一个client自己的Messenger对象
8、我们在第5步的时候获得了Service的Messenger对象,并通过它来给Service发送消息。这时候,我们将client的Messenger对象赋给待发送的Message对象的replyTo字段
9、在Service的Handler处理Message时将client的Messenger解析出来,并使用client的Messenger对象给client发送消息
这样我们就实现了client和Service的双向通信。client和Service都有自己的Handler和Messenger对象,使得对方可以给自己发送消息,值得注意的是client的Messenger是通过Message的replyTo传递给Service的。
Demo链接:http://pan.baidu.com/share/link?shareid=583593&uk=2953765628
绑定Service的三种实现方式之继承Binder类 2
继承Binder类实现绑定Service的应用场合:Service仅供自己使用(不对第三方程序开发)。
注:这种方式仅适用于client和service在同一个程序和进程的情况。
实现方法:
1、在Service中创建一个Binder的实例:
这个实例包含client可以调用的公共方法;
这个实例返回当前Service对象(该Service实例包含client可以调用的公共方法)
这个实例返回Service类中的一个类对象,而这个类对象包含client可以调用的公共方法
2、在Service的onBind函数中返回这个Binder实例
3、在client端的onServiceConnected方法中获得这个Binder实例,并通过这个Binder实例调用Service端的公共方法。
Demo请转至:http://pan.baidu.com/share/link?shareid=582094&uk=2953765628
绑定Service的三种实现方式之使用AIDL 3
AIDL全称为Android Interface Definition Language,它可以使你的程序实现进程间通信(IPC),并且在实现IPC的基础上允许多线程访问。
首先,我们要创建一个自己的.aidl文件(见Demo中的IRemoteService.aidl)。
定义AIDL文件与java中创建接口非常的类似。一般来说,aidl支持的数据类型有五种:java基本数据类型;String;CharSequence;List;Map。其中List和Map较为特殊(http://developer.android.com/guide/components/aidl.html#Create)。如果你使用的数据类型不是AIDL的基本数据类型,你必须要使用import语句将其导入,即使他们是在同一个package下。声明方法时,方法的参数可以零到多个,返回值可以是void;所有的非基本数据类型都需要指定是传入还是传出值(基本数据类型都是传入值;在AIDL文件中不能声明静态字段)
其次,我们要实现我们上面刚刚创建的接口(见Demo中StudentService中的mBinder)。
假设我们有一个AIDL文件叫IRemoteService.aidl,当我们编译我们的项目的时候,android的ant能将我们的AIDL文件生成为java文件(放在gen/下面)。这个java文件中有一个抽象内部类Stub(继承了Binder类)实现了我们的接口,并提供了一个asInterface方法将IBinder对象转化为我们的接口类型。因为实现我们的接口就转化为实现其抽象内部类Stub(Service端的业务函数全部在这里实现)。
再次,将我们的接口暴露给客户端(注意Demo在Server端AndroidManifest.xml中对StudentService的声明)
将我们的接口暴露给客户端实际上就是:在Service的onBind函数中将我们的Stub类的实例反出去。
这样,Service端的工作就完成了!
那么,怎样通过IPC传递对象呢(见Demo中的Student.java和Student.aidl)?
如果你想在进程间传递对象,那么对象就必须实现Parcelable接口。而实现这个接口需要我们完成以下几步:
1、在声明对象的时候实现Parcelable接口
2、实现writeToPacel方法
3、添加一个叫做CREATOR的静态变量(这个变量要实现Parcelable.Creator接口)
4、创建一个AIDL文件来声明这个实现了Parcelable接口的类
这样我们就可以在AIDL中使用对象了。
客户端怎么对Service端的方法进行调用呢?
其实很简单,只需要一下几步就可以了(见Demo中的Client中的代码)。
1、将Server端使用的.aidl文件拷贝到client程序中,如果你的aidl文件仅仅是对实现了Parcelable接口的类的说明,那么,对应的java文件也要拷贝过去。(注意包名,具体可参考Demo的client端对Sever端AIDL文件的导入)
2、编译client程序,将在gen/目录下生成AIDL对应的的类文件
3、实现ServiceConnection接口。在onServiceConnected方法中,使用AIDL生成的Java文件的函数(内部类Stub的asInterface)将onServiceConnected函数的中IBinder参数转化为AIDL生成的接口对象。
4、根据第3步得到的对象来调用AIDL中的函数。
5、调用bindService函数执行绑定操作(解绑使用unbindService函数)
到这里,AIDL的使用讲解就结束了。推荐你结合本文的Demo来读这篇文章,相信会让你受益匪浅的。
Demo链接:http://pan.baidu.com/share/link?shareid=587849&uk=2953765628
Service组件 总结 + 绑定理Service三种实现方式 Messager + Binder + AIDL的更多相关文章
- Django-多对多关系的三种创建方式-forms组件使用-cookie与session-08
目录 表模型类多对多关系的三种创建方式 django forms 组件 登录功能手写推理过程 整段代码可以放过来 forms 组件使用 forms 后端定义规则并校验结果 forms 前端渲染标签组件 ...
- django----多对多三种创建方式 form组件
目录 多对多三种创建方式 全自动 全手动 半自动 form组件 基本使用 form_obj 及 is_valid() 前端渲染方式 取消前端自动校验 正则校验 钩子函数(Hook方法) cleaned ...
- Django框架(十)--ORM多对多关联关系三种创建方式、form组件
多对多的三种创建方式 1.全自动(就是平常我们创建表多对多关系的方式) class Book(models.Model): title = models.CharField(max_length=32 ...
- 多对多三种创建方式、forms组件、cookies与session
多对多三种创建方式.forms组件.cookies与session 一.多对多三种创建方式 1.全自动 # 优势:不需要你手动创建第三张表 # 不足:由于第三张表不是你手动创建的,也就意味着第三张表字 ...
- 多对多的三种创建方式-forms相关组件-钩子函数-cookie与session
多对多的三种创建方式 1.全自动(推荐使用的**) 优势:第三张可以任意的扩展字段 缺点:ORM查询不方便,如果后续字段增加更改时不便添加修改 manyToManyField创建的第三张表属于虚拟的, ...
- spring Bean的三种配置方式
Spring Bean有三种配置方式: 传统的XML配置方式 基于注解的配置 基于类的Java Config 添加spring的maven repository <dependency> ...
- Hive metastore三种配置方式
http://blog.csdn.net/reesun/article/details/8556078 Hive的meta数据支持以下三种存储方式,其中两种属于本地存储,一种为远端存储.远端存储比较适 ...
- linux学习之centos(二):虚拟网络三种连接方式和SecureCRT的使用
---操作环境--- 虚拟机版本:VMware Workstation_10.0.3 Linux系统版本:CentOS_6.5(64位) 物理机系统版本:win10 一.虚拟网络三种连接方式 当在V ...
- Linux基石【第二篇】虚拟网络三种连接方式(转载)
在虚拟机上安装完Centos系统后,开始配置静态IP,以方便在本宿主机上可以访问虚拟机,在曲折的配置中,了解到虚拟机还有三种连接方式:Bridged,NAT和Host-only,于是,我又一轮新的各种 ...
随机推荐
- linux编程掌握常用命令
1)编译应用程序 make -f makefile_5_2 clean make -f makefile_5_2 2)关于共享目录 在linux虚拟机的/mnt/hgfs下可看到该文件夹 3)cd命令 ...
- vim 操作指令1
1.vim 在命令行中输入vim,进入vim编辑器 2.i 按一下i键,下端显示 –INSERT–插入命令,在vim中可能任意字符都有作用 3.Esc 退出i(插入)命令进行其它命令使用 4.:r f ...
- 怎样使用CMenu类
CMenu类从CObject类派生而来.为什么要使用CMenu类呢?AppWzard不是把菜单做好了吗?在资源编辑器上修改菜单不是很方便吗? 我是个vc++初学者,自从当斑竹以来,天天看贴子, ...
- 让动态创建的ActiveX控件响应Windows消息
当我们通过 CWnd::CreateControl() 动态创建 ActiveX 控件时, Windows 消息并不会被发送给我 们的由 CWnd 派生得控件类.例如,即使我们为 WM_KIL ...
- python中使用ctypes调用MinGW生成的动态链接库(dll)
关于gcc编译dll的我就不说了,网上举例一大堆,下面以g++为例. 假设有一个test.cpp文件如下: extern "C" { __declspec(dllexport) d ...
- hdu 4055 Number String(有点思维的DP)
Number String Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- STM32建立project库函数方法
(1)打开keilMDK主界面能够看到project中有一个默认的project,点击这个project名字,然后选择菜单Project->Close Project,就关闭掉这个project ...
- ORACLE 中的一些特殊符号
oracle通配符,运算符的使用 用于where比较条件的有: 等于:=.<.<=.>.>=.<> 包含:in.not in exists.not exists 范 ...
- extjs desktop startmenu (開始菜单)
extjs desktop 的開始菜单 二级菜单,仅仅是简单演示实现原理,如 须要动态生成,自己改造就可以,下面基本方法原理: 首先 建立一个js文件 生成開始菜单数据: function Get ...
- java学习笔记06--正则表达式
java学习笔记06--正则表达式 正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证.拆分.替换等操作. 例如:现在要去判断一个字符串是否由数字组成,则可以有以下的两种做法 不使用正则 ...