Service
1.Service生命周期
Service完整生命周期从onCreate()开始到onDestroy结束,在onCreate( )中完成Service的初始化工作,在onDestroy( )中释放所有占用的资源。
活动生命周期从onStart()开始,但没有与之对应的“停止”函数,因此可以粗略的认为活动生命周期是以onDestroy( )标志结束。
2.Service的使用方式有两种
启动方式
绑定方式
**启动方式**
通过调用Context.startService()启动Service,通过调用Context.stopService()或者Service.stopSelf()停止Service.因此Service一定是由其他的组件启动的,但停止过程可以通过其他组件或自身完成
在启动方式中,启动Service的组件不能够获取到Service的对象实例,因此无法调用Service中的任何函数,也不能够获得Service中的任何状态和数据信息。
能够以启动方式使用的Service,需要具备自管理的能力,而且不需要通过函数调用来获取Service的功能和数据。
**绑定方式**
Service的使用时通过服务链接(connetction)实现的,服务链接能够获取Service的对象实例,因此绑定Service的组件可以调用Service中实现的函数,或之间获取Service中的状态和数据信息。
使用Service的组件通过Context.bindService()建立服务链接,通过Context.unbindService()停止服务链接
如果在绑定过程中Service没有启动。Context.bindService()会自动启动Service,而且同一个Service可以绑定多个服务链接,这样可以同时为多个不同的组件提供服务。
**启动方式和绑定方式的结合**
这两种使用方法并不是完全独立的,在某些情况下可以混合使用。
以MP3为例,在后台工作的Service通过Context.startService()启动某个音乐播放,但在播放过程中如果用户需要暂停音乐,则需要通过Context.bindService()获取服务链接和Service对象实例,进而通过调用Service对象实例中的函数,暂停音乐播放过程,并保存相关信息。
在这种情况下,如果调用Context.stopService()并不能够停止Service,需要在所有的服务连接关闭后,Service才能够真正的停止。
3.本地服务
本地服务的调用者和服务都在同一个程序中,是不需要跨进程就可以实现服务的调用。
本地服务涉及服务的建立、启动和停止,服务的绑定和取消绑定,以及如何在线程中实现服务。
**服务管理**
服务管理主要指服务的启动和停止
首先说明如何在代码中实现Service。Service是一段在后台运行、没有用户界面的代码。
在完成Service代码和在AndroidManifest.xml文件中注册后,下面来说明如何启动和停止Service。有两种方式,分别是 显式启动和隐式启动。
显式启动需要在Intent中指明Service所在的类,并调用startService(Intent)启动Service,实例代码如下:
final Intent serviceIntent=new Intent(this,RandomService.class);
startService(serviceIntent);
上面代码中,Intent指明了启动的Service所在类为RandomService
隐式启动则需要在注册Service时,声明Intent-filter的action属性
在隐式启动Service时,需要设置Intent的action属性,这样则可以在不声明Service所在类的情况下启动服务。实例代码如下:
final Intent serviceIntent=new Intent();
serviceIntent.setAction("com.RandomService");
如果Service和调用服务的组件在同一个应用程序中,可以使用显式启动和隐式启动,显式启动更加易于使用,且代码简洁。如果服务和调用服务的组件在不同的应用程序中,则只能使用隐式启动。
无论是显式启动还是隐式启动,停止Service的方法都是相同的,将启动Service的Intent传递给stopService(Intent)即可。实例代码如下:
stopService(serviceIntent);
在首次调用startService(Intent)启动Service后,系统会先后调用onCreate()和onStart()
如果是第二次调用startService(Intent),系统则仅调用onStart(),而不再调用onCreate()
在调用stopService(Intent)停止Service时,系统会调用onDestroy()
无论调用过多少次startService(Intent),在调用stopService(Intent)时,系统仅调用一次onDestroy()
**使用线程**
在Android系统中,Activity、Service和BroadcastRecever都是工作在主线程上的,因此任何耗时的处理过程都会降低用户界面的响应速度,甚至导致用户界面失去响应。
当用户界面失去响应超过5秒,Android系统会允许用户强行关闭应用程序。
因此,较好的解决方式是将耗时的处理过程转移到子线程上,这样可以缩短主线程的事件处理时间,从而避免用户界面长时间失去响应。
“耗时的处理过程”一般指复杂运算过程,大量的文件操作,存在演示的网络通讯和数据库操作等等。
线程是独立的程序单元,多个线程可以并行工作。在多处理器系统中,每个CPU单独运行一个线程,因此线程是并行工作的。
但在单处理器系统中,处理器会给每个线程一小段时间,在这个时间内线程是被执行的,然后处理器执行下一个线程,这样就产生了线程并行运行的假象。
无论线程是否真的并行工作,在宏观上可以认为子线程是独立于主线程,且能与主线程并行工作的程序单元。
在Java语言中,建立和使用线程比较简单,首先需要实现java的Runnable接口,并重载run()函数,在run()中放置代码的主体部分。
private Runnable backgroudWork=new Runnable(){
@Override
public void run()
{
//过程代码
}
}
然后创建Thread对象,并将Runnable对象作为参数传递给Thread对象
在Thread的构造函数中,第1个参数用来表示线程组,第2个参数是需要执行的Runnable对象,第3个参数是线程的名称
private Thread workThread;
workThread=new Thread(null,backgroudWork,"workThread");
最后调用
workThread.start();
当线程在run()方法返回后,线程就自动终止了
当然也可以调用stop()在外部终止线程,但是这种方法并不推荐使用,因为这个方法并不安全,有一定可能性会产生异常。
最好的方法是通知线程自行终止,一般调用interrupt()方法通告线程准备终止,线程会释放它正在使用的资源,在完成所有的清理工作后自行关闭。
workThread.interrupt()
其实interrupt()方法并不能直接终止线程,只是改变了线程内部的一个布尔值,run()方法能够检测到这个布尔值的改变,从而在适当的时候释放资源和终止线程。
在run()中的代码一般通过Thread.interrupted()方法查询线程是否被中断
一般情况下,子线程需要无限运行,除非外部调用interrupt()方法中断线程,所以通常会将程序主体放置在while()函数中,并调用Thread.interrupted()方法判断线程是否应被中断
下面的代码中,以1秒为间隔循环检测线程是否被中断
public void run()
{
while(!Thread.interrupted())
{
//过程代码
Thread.sleep(1000);
}
}
当线程在休眠过程中线程被中断,则会产生InterruptedException异常
因此代码中需要捕获InterruptedException异常,保证安全终止线程
public void run()
{
try{
while(!Thread.interrupted())
{
//过程代码
Thread.sleep(1000);
}
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
使用Handler更新用户界面
Handler允许将Runnable对象发送到线程的消息队列中,每个Handler实例绑定到一个单独的线程和消息队列上
4.远程服务
**进程间通信**
在Android系统中,每个应用程序在各自的进程中运行,而且处于安全原因的考虑,这些进程之间彼此是隔离的,进程之间传递数据和对象,需要使用Andorid支持的进程间通信(IPC)机制
在Unix/Linux系统中,传统的IPC机制包括共享内存、管道、消息队列和socket等等,这些ipc机制虽然被广泛使用,但仍然存在着固有的缺陷,如容易产生错误、难于维护等等。
在Android系统中,没有使用传统的ipc机制,而是采用Intent和远程服务的方式实现IPC,使应用程序具有更好的独立性和鲁棒性。
Android系统允许应用程序使用Intent启动Activity和Service,同时Intent可以传递数据,是一种简单、高效、易于使用的IPC机制。
Android系统的另一种IPC机制就是远程服务,服务和调用者在不同的两个进程中,调用过程需要跨越进程才能实现
**服务的创建和调用**
Android系统中使用远程服务,一般按照以下3个步骤实现
1.使用AIDL语言定义远程服务的接口
2.根据AIDL语言定义的接口。在具体的Service类中实现接口中定义的方法和属性。
3.在需要调用远程服务的组件中,通过相同的AIDL接口文件,调用远程服务
在Android系统中,进程之间不能直接访问相互的内存控件,因此为了使数据能够在不同进程中传递,数据必须转换成能够穿越进程边界的系统级原语,同时,在数据完成进程边界穿越后,还需要转换回原有的格式
AIDL是Android系统自定义的接口描述语言,可以简化进程间数据格式转化和数据交换的代码,通过定义Service内部的公共方法,允许在不同进程间的调用者和Service之间相互传递数据。
AIDL的IPC机制、COM和Corba都是基于接口的轻量级进程通信机制
AIDL语言的语法和java的接口定义非常相似,唯一不同之处是AIDL允许定义函数参数的传递方向
AIDL支持3种方向:in、out和inout
标识为in的参数将从调用者传递到远程服务中
标识为out的参数将从远程服务传递到调用者中
标识为inout的参数将先从调用者传递到远程服务中,再从远程服务返回给调用者
如果不标识参数的传递方向,默认所有函数的传递方向为in
处于性能方向的考虑,不要在参数中标识不需要的传递方向
远程服务的创建和调用需要使用AIDL语言,一般分为一下几个过程
1.使用AIDL语言定义远程服务的接口
2.通过继承Service类实现远程服务
3.绑定和使用远程服务