Service和Thread区别
Thread
进程是系统最小资源分配单位,而线程是则是cpu调度的最小的执行单位,线程必须依赖进程,在android中启动一个app就是一个进程,我们通常所说的UI线程就是app启动后创建的主线程,线程需要的资源通过它所在的进程获取。线程可以理解成是在进程中独立运行的子任务。一旦在android的activity中创建一个线程,那它将与activity独立出来,如果一直执行耗时操作,并且activity已被finish,它还会一直执行。
Service
android的四大组件之一,需要在清单文件进行配置,它可以理解为一个没有UI界面的Activity,长期运行在后台,和Thread相同的是它的运行也不依附于Activity,也就是说他并没有失去焦点和不可见后这种生命周期,即使应用程序退居后台,它也不会被销毁和停止运行。这就很适合做一些音乐播放和下载网络数据的功能,但是他是在主线程中执行的,在做一些耗时任务时也会造成应用程序的ANR,通常的做法都是在Service中开启子线程执行耗时操作。在用普通方式启动的服务时,当app进程被杀死,它也随之停止运行。(bind方式启动在后面)
三种方式启动服务:
首先明确:不管是以哪种方式启动服务,同一个服务只能被创建一次,但是可以被启动多次,如果系统发生异常导致服务终止后,如果内存足够,服务所在的进程会重新创建服务。如果是用户主动销毁的,则不会重新创建。
用普通方式启动的服务:
android这种方式是用startService()进行启动,一旦启动,该Service将不与任何组件相关,启动服务的组件已经被销毁也一直运行在后台
生命周期:onCreate()- >onStartCommand()->onDestroy()
fun test(view: View) {
startService(Intent(this, MyService::class.java))
stopService(Intent(this, MyService::class.java))
startService(Intent(this, MyService::class.java))
startService(Intent(this, MyService::class.java))
stopService(Intent(this, MyService::class.java))
}
class MyService: Service(){
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
println("Service Create ThreadID:${Thread.currentThread().id}")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
println("Service startcommand")
return super.onStartCommand(intent, flags, startId)
}
override fun onUnbind(intent: Intent?): Boolean {
return super.onUnbind(intent)
}
override fun onDestroy() {
println("Service Destroy")
super.onDestroy()
}
}
注册:
<service
android:name="com.example.service.MyService"
android:enabled="true"
android:exported="true">
</service>
<!--enabled:表示系统是否能够实例化(使用)该组件
exported:表示该服务是否能够被其他应用程序组件所调用或者交互-->
结果:
2020-11-26 10:36:19.277 23919-23919/com.example.ha I/System.out: Service Create ThreadID:2
2020-11-26 10:36:19.277 23919-23919/com.example.ha I/System.out: Service startcommand
2020-11-26 10:36:19.278 23919-23919/com.example.ha I/System.out: Service Destroy
2020-11-26 10:36:19.281 23919-23919/com.example.ha I/System.out: Service Create ThreadID:2
2020-11-26 10:36:19.281 23919-23919/com.example.ha I/System.out: Service startcommand
2020-11-26 10:36:19.281 23919-23919/com.example.ha I/System.out: Service startcommand
2020-11-26 10:36:19.282 23919-23919/com.example.ha I/System.out: Service Destroy
绑定方式启动Service
此种方式使用bindService()启动服务,多个组件可同时绑定同一个Service,当Service没有了绑定者将会自行销毁
使用unbindService()可解除绑定
以startService方式启动的服务基本与其他组件独立开来,但bindService不同,在 bindService(Intent service, ServiceConnection conn, int flags)方法参数中可以看到第二个参数为接口ServiceConnection, 这是让用户自定义对绑定者和Service连接状态的监听,该接口通常要重写onServiceConnected(ComponentName name,IBinder service)和onServiceDisconnected(ComponentName name)方法,其中的IBinder对象就是自定义Service中onBind函数返回的对象,通过这个对象我们就可以实现与Service之间的通信。
生命周期:onCreate()->onBind()->onUnbind()->onDestroy()
fun test(view: View) {
bindService(Intent(this, MyService::class.java),object :ServiceConnection{
override fun onServiceDisconnected(name: ComponentName?) {
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Toast.makeText(this@MainActivity, "连接成功", Toast.LENGTH_SHORT).show()
val myBinder = service as MyService.MyBinder
myBinder.test("可以")
}
}, Context.BIND_AUTO_CREATE) //Context.BIND_AUTO_CREATE指绑定时自动创建Service
}
class MyService: Service(){
val binder = MyBinder()
override fun onBind(intent: Intent?): IBinder? {
println("Service onBind")
return binder
}
override fun onCreate() {
super.onCreate()
println("Service Create ThreadID:${Thread.currentThread().id}")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
println("Service startcommand")
return super.onStartCommand(intent, flags, startId)
}
override fun onUnbind(intent: Intent?): Boolean {
return super.onUnbind(intent)
}
override fun onDestroy() {
println("Service Destroy")
super.onDestroy()
}
class MyBinder : Binder() {
fun test(str:String){
Log.i("Service:", str)
}
}
}
2020-11-26 14:06:05.905 30065-30065/com.example.ha I/System.out: Service Create ThreadID:2
2020-11-26 14:06:05.906 30065-30065/com.example.ha I/System.out: Service onBind
2020-11-26 14:06:09.311 30065-30065/com.example.ha I/System.out: Service onUnBind
2020-11-26 14:06:09.312 30065-30065/com.example.ha I/System.out: Service Destroy
混合调用
可以先startService再bindService这样就走onStartCommand()方法了
同时保证服务在后台长期运行还可进行通信,结束后应先解绑在停止服务
2020-11-26 14:08:00.294 30734-30734/com.example.ha I/System.out: Service Create ThreadID:2
2020-11-26 14:08:00.294 30734-30734/com.example.ha I/System.out: Service startcommand
2020-11-26 14:08:00.295 30734-30734/com.example.ha I/System.out: Service onBind
2020-11-26 14:08:00.875 30734-30734/com.example.ha I/System.out: Service onUnBind
2020-11-26 14:08:00.875 30734-30734/com.example.ha I/System.out: Service Destroy
Android 中进程的级别以及 Service 的优先级
- 前台进程
杀死前台进程需要用户交互,因为前台进程的优先级是最高的。 - 可见进程.
如果一个进程不含有任何前台的组件,但仍可被用户在屏幕上所见。 - 服务进程
进程中运行着一个service,这个service是通过 startService() 开启的,并且不属于上面两种较高优先级的情况,这个进程就是一个服务进程。 - 后台进程
如果进程不属于上面三种情况,但是进程持有一个用户不可见的activity - 空进程
如果一个进程不包含任何活跃的应用组件,则认为是空进程。当系统进程空间紧张时,会依照优先级自动进行进程的回收。
- 若直接在Activity中新开一条线程来做耗时操作,当该Activity退出到桌面或其他情况时将成为一个后台进程。
- 若在Service中新启动线程,则此时Android会依据进程中当前活跃组件重要程度,将其判断为服务进程,优先级比(1)高。
- Activity中启动service,然后在Service中新启动线程,当activity退出时Service继续持有线程对象,只需重新绑定即可拿到线程对象,而不会丢失线程对象
保证Service不死常用技巧
- 提升优先级,在清单文件的过滤器中添加属性android:priority=“1000”
- 在onStartCommand()里面调用startForeground()把Service提升为前台进程,然后在相应地方调用stopForeground()
- onStartCommand方法,返回START_STICKY。
onStartCommand()方法,返回的是一个int整形。
这个整形可以有以下四个取值:
- :START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
- START_NOT_STICKY:“非粘性的”。如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service。
- START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将保存下来的Intent的值传入。
- START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
- 在onDestroy方法里发广播重启service。
- 监听系统广播执行我们自定义的广播接收者判断Service状态
- 将app变成系统级应用程序 清单文件加上 android:persistent=”true”,将进程设为常驻内存进程,并将APK安装到/system/app
- 守护服务,当服务A即将死亡时开启服务B,服务B中开启并绑定服务A
Server里发消息给Activity :将Acitivity中持有Handler的对象置为静态变量