服务
- 服务是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互而且还要求长期运行的任务。
- 服务并不是运行在一个独立的进程当中的,而是依赖于创建服务时所在的应用程序进程,当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止运行
- 服务并不会自动开启线程,所有的代码都是默认运行在
主线程
当中的。也就是说,我们需要在服务的内部手动创建子线程,并在这里执行具体的任务,否则就有可能出现主线程被阻塞的情况
创建一个服务
创建
默认代码
1 | public class MyService extends Service { |
这个服务类是继承于Service
类的,其中必须实现抽象方法onBind()
服务中最常见的三个重写方法:
onCreate()
:创建时调用onStartCommand()
:启动时调用onDestroy()
:销毁时调用
注册服务(按照上图创建会自动注册)
1 | <service |
Exported
表示是否允许其他程序访问此服务Enabled
表示是否启用此服务
启动和停止服务
布局
1 |
|
活动
1 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { |
修改服务
1 | public class MyService extends Service { |
服务和活动通信
通信需要在服务中借助onBind()
方法,一般需要创建一个专门的Binder
对象管理。
模拟下载功能:
服务类
1 | public class MyService extends Service { |
布局
1 |
|
活动
1 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { |
分析
- 创建了
ServiceConnected
匿名类,重写了里面的onServiceConnected()
和onServiceDisconnected()
方法,这两个方法会在绑定成功和连接断开时调用 在
onServiceConnected()
将Service
向下转型为自定义的DownloadBinder
实例,然后用这个实例就能调用在DownloadBinder
中的任何方法【必须先绑定】bindService()
可以将活动和服务绑定,第一个参数是Intent对象
【和服务联系起来】,第二个参数是创建好的ServiceConnection
实例【指定要绑定的服务】,第三个参数是一个标志位,传入BIND_AUTO_CREATE
表示绑定后自动创建服务【onCreate()
执行,onStartCommand()
不执行【即创建而不启动】】- 解绑
unBindService()
,参数就是绑定好的ServiceConnection
实例 - 一个服务可以与不同的活动绑定,绑定后会获取到相同的实例
服务的声明周期
- 调用
Context.startService()
服务就会启动并回调onStartCommand()
方法,若服务还未创建过,就会先执行onCreate()
- 服务启动后一直处于运行状态,直到
Context.stopService()
或stopSelf()
被调用 - 每个服务都只会存在一个实例,不管调用多少次
startService()
,都只会存在一个实例,关闭只需一次 - 通过
Context.bindService()
获取服务的持久连接,就会回调服务的onBind()
方法,onBind()
返回一个IBinder
对象实例,就能实现自由通信了 - 调用
Context.stopService()
服务就会被销毁并回调onDestroy()
方法 - 类似的,被绑定的服务执行
unbindService()
也会被销毁,而且回调onDestroy()
- 如果一个服务既执行了
startService()
,也执行了bindService()
,那么,销毁这个服务就必须都执行stopService()
和unbindService()
才能被销毁,onDestroy()
才能被执行
前台服务
- 前台服务和普通服务最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果(像天气类app就要用到前台服务)。
- 前台服务可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收
Demo code
- 添加权限
1 | <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> |
- 代码
1 | public void onCreate() { |
- 运行
使用IntentService
- 主线程处理耗时任务很容易出现ANR(
Application Not Responding
),所以推荐在每个服务的具体方法里开启子线程,即以下形式:
1 | public class MyService extends Service{ |
- 但是有时总是忘记开多线程或者自动停止。为了解决这个问题,Android提供了
IntentService
类解决这个问题。
Demo
- 新建一个
MyIntentService
类继承自IntentService
:
1 | public class MyIntentService extends IntentService { |
- 注册活动
1 | <service android:name=".MyIntentService"/> |
- 布局中添加一个按钮
1 | <Button |
- 点击事件
1 |
|
运行
可以看到
MyIntentService
这个服务是在子线程中运行的