Service Modules(服务模块)

wxws

Member
Licensed User
Longtime User
Basic4android v1.2 加入了Service Modules的支持
Service Modules在应用程序和进程生命周期中扮演了重要的角色
在阅读此教程之前,你必须先阅读一下Android进程及activitys 生存周期
写在activities 模块里的代码会在activity不可见时暂停,所以如果你只用activitys,你的应用程序无法在不可见(后台)时
运行任何代码(被暂停了).
Services 的生存周期是不受当前可见的activity影响的.这就是说,它能允许你在后台运行任务.
Services 通常用状态栏通知与用户交互.Services没有任何可见元素(控件),同时也不允许使用任何对话框(除了toast message) *注 toast message即浮动消息,不会获得焦点,不影响用户的输入等操作,主要用于一些帮助/提示.
注意:如果一个在Service代码中产生了一个错误,它不会象你通常见到跳出一个"时否继续"的对话框,而是跳出一个"应用程序已崩溃"的对话框.

在你准备研究这些细节之前,我很高兴的对你说,使用Services远比它听起来更简单.
事实上,很多任务运行在Services 里比运行在activity里更简单.因为Services不会在用户旋转屏幕时总是paused(暂停)和恢复(resumed),也就是说它不需要任何特别的代码用于处理这些状态.
Service module中的代码和别的代码没什么区别,运行在同样的进程中,同样的线程里.

有一点需要明确的知道,Android系统在低内存时会自动结束哪些进程(当低内存而一个新的应用程序启动时)
应用程序会处于下列几种状态中
- Foreground(前台激活) - 当前用户正在使用应用程序(应用程序其中一个activity前台可见)
- Background(后台) - 此应用程序没有任何一个可见的activity,但是它启动了一个后台Service.
- Paused(暂停) - 此应用程序没有任何一个可见的activity,后台也没有Service

Paused processes(暂停的进程)是被系统最先被结束的.如果释放出来的内存还是不足,则再结束后台进程.
前台激活中的进程通常是不会被结束的.

一会你会发现,一个后台Service同样能把进程切换至前台.

添加一个Service module,选择Project - Add New Module - Service Module.
一个新的Service module模板如下:
B4X:
Sub Process_Globals

End Sub

Sub Service_Create

End Sub

Sub Service_Start

End Sub

Sub Service_Destroy

End Sub
Sub Process_Globals 这里定义Service 全局变量.这里不象activity的全局定义,不能定义任何activity对象(估计是view之类可见对象).
Sub process globals 只能用于定义变量.任何其它代码都会出错.
Process_Global 中定义的变量可以在任何其它模块中调用,并且生存周期同进程一样.

Sub Service_Create 会在第一次调用service时调用.这里可以初始化全局变量.一但service开始,会一直存在,直到你调用StopService或者整个进程被销毁. (也就是说,第一次调用service会调用create,再次调用就不会再进入create了.并且这里初始化的全局变量会一直保留,不会被回收,直到进程结束)
Sub Service_Start 当你调用StartService (或 StartServiceAt)时每次都会被调用.这里的代码在进程被切换到后台后还是会继续运行. 这意味着,系统会不结束你的进程,直到这里的代码运行结束. 如果你计划每几分钟或几小时后再次运行,你需要在这个过程里使用StartServiceAt.(也就是说代码都运行完后,最后一句加上StartServiceAt,相当于定时器,定义一下下一次在几分钟或几小时后再次运行)

Sub Service_Destroy 在你调用StopService时调用. 这个service不再运行,直到你再次调用 StartService.(停止后再开始,会再次调用 Sub Service_Create). * 也就是说这个service会重新初始化.
为什么要使用Service,什么情况下需要使用service

这里有4种service使用案例.
- 业务代码与界面分离.一个没有UI的service比一个activity更容易.因为不需要处理前台切换,屏幕旋转等带来的状态变化,还有同常它只需初始化一次,不需要频繁的创建,销毁.
你可以在Activity_Create事件里调用StartService开始一个service.
一个良好的设计是,在一个activity的Sub Activity_Resume事件里从service里取需求的数据.
activity能从service的process global 里取自已需求的数据,或者使用CallSub函数调用service的函数.

- 操作时间很长.比如 下载一个很大的文件.这个案例里,你可以在service module里调用Service.StartForeground ,他会把你的进程切换至前台状态以确保系统不会结束掉它.不过别忘了,最后要调用Service.StopForeground.

- 计划任务. 通过调用 StartServiceAt 你可以计划你的service在某个时间点启动.通过调用StartServiceAt,你可以定时重复启动你的service.(比如,每分钟检测一下是不是有更新)

- 开机启动.设置 #StartAtBoot 属性为 True,我们的service 会在系统启动后自动启动.

通知(Notifications)

activities 和 services都能发送状态栏通知.
service通常都是用通知与用户交互.通知有文字也有图标,当用户下拉状态栏时就会看到.

通知的示例 (使用默认图标):

notification_1.png


notification_2.png

用户能通过点击通知进入我们设置好的的activity.

通知使用的图标文件,我们需要手动放在如下目标: <project folder>\Object\res\drawable.

访问其它模块
Process global objects(全局定义) 是公共的,能被其它任何模块访问.
通过使用CallSub函数,你可以调用其它不同模块中的函数(activity模块里的函数不是public公开的,所以不能通过XXX.XXX方式调用)
这里有个限制,只能调用非暂停中的模块.意思就是说,一个activity永远不能调用到另一个activity中的函数.因为一个程序只有一个activity在前台运行.
但是一个activity能访问一个正在运行的service,一个service同样能访问一个正在运行的activity.(这意味着,service和当前aitivity能互相访问,而不能访问其它activity)
注意 如果目标控件(模块)被暂停,则会返回一个空字符串.
不会有任何异常抛出.
你可以使用IsPause函数来确认目标module是不是在暂停状态中.(也就是说如果一个service执行完毕,想通知界面时,需要先检查一下是否处于暂停状态,也就是被用户切换至后台时是无法正确访问的,这里指可视控件,变量等等不在内)

比如,当一个service下载了一些新的信息,它可以这样:
B4X:
CallSub(Main, "RefreshData")

如果Main activity 正在运行状态,它会从service的全局变量中获得数据,然后更新显示.
当然,同样可以把新的数据传入activity的函数中.这样比一直把数据保存在全局变量中来的好.这样可以让activity自已控制,什么时候更新.(因为当数据来的时候,activity可能处于暂停状态,也就是在后台).

注意 不能使用CallSub调用一个Code module里的函数(代码模块可以直接用xxx.xx来调用)

示例:
Downloading a file using a service module(使用service模块来下载一个文件)
Periodically checking Twitter feeds(定时检查twitter)
 
Last edited:
Top