经验来自于不断的实践,经过实践检验之后,我们在使用过程中,会自然或者不自然的发现一些重要的东西,这里分析一下笔者在使用Service的时候,用到过或者关注过的一些特性与要点。
1、Service的优先级
在Android系统中,内存环境是有限的,如果后台的应用太多,系统资源不够用,一些优先级比较低的应用或者服务会被系统回收,系统资源被释放。优先级是操作系统中的概念,大家不懂的按照字面意思理解就行了,就是优先权的意思。
在Android系统中,系统应用的权限是最高的,一般不会被回收,但是一些预装的应用,优先级也挺高的,会比较占用资源。这里,我们简单说说Service在优先级上的四个应用场景上的问题:
1.1 如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。
1.2 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
1.3 如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
1.4 如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
2、Service与Thread
Service是Android应用的四大组件之一,意思是服务,在后天运行,一般前台看不见,但是部分如酷狗音乐播放器,墨迹天气,360手机卫士等应用也还有前台页面,当然这是后话,我们重点说说Service与Thread线程之间的联系与区别。
可能刚开始学习Service的时候,会误以为Service与Thread是一样的概念,因为两者都不可见的在背后做一些操作,但是事实上,两者没有丝毫的关系,如果非要说有,也就是你所看到的,两者会在后台偷偷做些事情。
Thread:线程,是CPU可执行的最小单元,当我们new 出来一个线程的时候,就会在CPU中分配单元,分配操作任务。
Service:服务,是Android的一个组件,能够在后台运行一些东西,我们作为用户是不可见的。
在这里,我们要提出一个意味,似乎Thread可以代替了Service,实际上不完全是的。比如,Service我们应用中的任何Activity都可以调用,并且容易监控(Service的生命周期),但是Thread可以说当我们创建之后,除了创建者之外,你已经很难控制他了。如果这个线程没有执行完,用户退出了应用,也会出现一堆问题。
当我们在使用Service的时候,耗时的操作,还是会放到线程中去处理。
3、前台运行的Service
上面我们提到了诸如360手机卫士这样的软件,始终会在我们的任务通知栏占有一个位置,或者在我们界面上有一个精灵球。额,实际上这里就是开启了一个服务。也许我们会有疑问,不是一直强调说Service与Activity最大的不同就是Service是后台运行的吗???
额,话是这么说的,但是实际上你需要Service能够显示成为前台应用的,也是有方法的。至于为什么会有这样的需求被提出来,也是因为随着系统的应用,开发者的需求被深度挖掘出来了吧。这里,我们简单说一下在360手机卫士中,如何实现的常驻通知栏,并且显示给用户看的。代码如下:
Notification notification = new Notification(R.drawable.ic_launcher, "有通知到来", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, "这是通知的标题", "这是通知的内容", pendingIntent);
startForeground(1, notification);
这里提供一个代码段,这段代码段在Android2.0之后都是可以执行的,额,想必现在也没人在使用1.X的系统做开发了吧???读者可以自行去检验,这里就不提供过多的代码了。也就不贴图演示了。
要从前台删除服务,需要调用stopForeground()方法,这个方法需要一个布尔型参数,指示是否删除状态栏通知。这个方法不终止服务。但是,如果你终止了正在运行的前台服务,那么通知也会被删除。
4、远程的Service
远程的Service?额,这里我们要先提到一个概念,Service可以按照多种形式分类,这里远程相对应的是本地Service,也就是local为标识符号,远程的remote。在传统的local服务中,如果我们要使用比较耗时的操作,应用程序会出现ANR,就是访问没有应答,你只好FC了。
为什么在Service中也会出现ANR呢?这种反应不应该都是Activity才会出现的么?额,上面说过了,Service并不是一个独立的线程,它是运行在或者说寄生在Activity的主线程的。我们知道,在主线程上,是不允许有耗时的操作的,所以,你现在懂了,上面我们提到的Service与Thread的区别了么。
这里提到的远程service,就是在使用这个Service的时候,新建了一个新的线程去完成任务!!爽吧,来看看如何使用:
<service
android:name="com.test.service.MyService"
android:process=":remote" >
</service>
好吧,你没有看错,实际上这只是在xml文件中添加了一个属性:android:process=":remote" 。
这个时候,也许你会想,哇靠,那以后还用Thread干嘛,直接用远程Service不就行了?额,实际上,建议少用这种service,为什么呢?我们前面提到过,Thread在创建之后容易失控,不受到我们的限制,这里提到的远程service也会出现这种问题。
远程Service会出现一个问题,就是我们只能通过startService()去启动,而不能使用bindService()去启动,为什么?因为start的时候,你可以新开一个线程,而bind是两个线程在一起的,必须要在一起,因为是生命共同体!!!但是远程service是单独的线程,所以,不能用,当然你可以强用,Android会直接崩溃。嘿嘿,开个玩笑。