#service从入门到放弃
微信公众号:没有
如果你觉得此文章对你有帮助,欢迎点赞
###service简介
service和activity 、contentProvider、BroadcastReceiver并称为Android四大组件,其地位不言而喻,在使用中也确实举足轻重。service的直接翻译为服务,它是一种在后台执行长时间运行才最而没有UI的应用组件。service可以理解为没有界面的activity,非常适合用于执行不需要交互界面且长期后台运行的任务。service不能运行在独立的进程中,需要依赖创建服务时所在的应用程序进程。服务器不会自动开启工作线程,它和activity一样,创建之后会创建一个主线程,工作线程需要我们手动创建服务可由其他应用组件启动(如Activity),启动方式后边详细讲。
service基本上分为两种状态:
如果一个service是通过startService() 方式启动的,服务当前的状态即为“启动”状态。一旦启动,服务即可在后台长期运行,急事启动该服务的组件已经被销毁,也无任何影响,因为服务此时不依赖任何组件,是独立运行的,除非手动调用停止或者强行停止运行应用才能停止服务,已启动的服务通常是执行单一操作,而且不会把结果返回给调用方。
如果一个service是通过bindService() 方式启动的,则该服务是“绑定”状态。绑定的服务提供了 客户端-服务端的接口,允许组件与服务器进行交互、发送请求和获取数据,并且可以利用IPC(进程通信机制)进行跨进程执行这些操作。此服务生命周期与绑定该服务的组件一致,组件销毁后绑定的服务也会停止运行。
步骤如下:
class BookService : Service() {
val TAG = "BookService"
override fun onBind(intent: Intent): IBinder? {
LogUtils.i(TAG,"onBind")
return null
}
override fun onCreate() {
super.onCreate()
LogUtils.i(TAG,"onCreate")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
LogUtils.i(TAG,"onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
LogUtils.i(TAG,"onDestroy")
}
}
private val TAG = "MainActivity"
val RECEIVE_MESSAGE_CODE : Int = 0x0002
//客户端的消息处理
class ClientHndler : Handler(){
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
LogUtils.i(TAG,"clientHndler")
when (msg?.what) {
RECEIVE_MESSAGE_CODE -> {
LogUtils.i(TAG,"这是来自服务端的问候:" + msg.obj)
}
else -> {
LogUtils.i(TAG,"未接收到服务端的问候!!!")
}
}
}
}
//初始化客户端的messenger
val clientMessenger = Messenger(ClientHndler())
class MainActivity : AppCompatActivity(),ServiceConnection{
override fun onServiceDisconnected(p0: ComponentName?) {
//TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
LogUtils.i(TAG,"onServiceDisconnected")
}
private lateinit var movieService: MovieService
override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
//TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
LogUtils.i(TAG,"onServiceConnected")
var movieBinder = p1 as MovieService.MovieBinder
movieService = movieBinder.getMovieService()
}
class Conn : ServiceConnection{
val TAG = "Conn"
override fun onServiceDisconnected(p0: ComponentName?) {
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
LogUtils.i(TAG,"onServiceDisconnected")
}
lateinit var serviceMessenger: Messenger
override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
LogUtils.i(TAG,"onServiceConnected")
serviceMessenger = Messenger(p1)
}
}
val conn = Conn()
private var bookbinders = Intent()
private var movieBinders = Intent()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
LogUtils.i(TAG,"onCreate")
//直接启动service
btn_start.setOnClickListener {
bookbinders.setClass(this,BookService().javaClass)
startService(bookbinders)
}
//停止service
btn_stop.setOnClickListener {
stopService(bookbinders)
}
//绑定service
btn_bind.setOnClickListener {
movieBinders.setClass(this,MovieService::class.java)
bindService(movieBinders,this,Service.BIND_AUTO_CREATE)
}
//解除绑定
btn_unbind.setOnClickListener {
unbindService(this)
}
//获取数据
btn_getdata.setOnClickListener {
val count = movieService.movieName
println("从service获取的count===$count")
}
//msg bind
btn_msg_bind.setOnClickListener {
var intent = Intent()
intent.setClass(this@MainActivity,MusicService::class.java)
bindService(intent,conn,Service.BIND_AUTO_CREATE)
}
//给service发送消息
btn_send_msg.setOnClickListener {
val message = Message.obtain(null, SEND_MESSAGE_CODE, 0, 0)
message.obj = "来自客户端的问候!!!"
message.replyTo = clientMessenger
conn.serviceMessenger.send(message)
}
//取消绑定
btn_msg_unbind.setOnClickListener {
unbindService(conn)
}
}
override fun onStart() {
super.onStart()
LogUtils.i(TAG,"onStart")
}
override fun onRestart() {
super.onRestart()
LogUtils.i(TAG,"onRestart")
}
override fun onResume() {
super.onResume()
LogUtils.i(TAG,"onResume")
}
override fun onPause() {
super.onPause()
LogUtils.i(TAG,"onPause")
}
override fun onDestroy() {
super.onDestroy()
LogUtils.i(TAG,"onDestroy")
}
}
接下来看一下service启动的过程:
点击“启动service”按钮:查看logcat:
09-25 14:03:09.307 16466-16466/com.xyd.servicedemo I/BookService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.BookService.onCreate(BookService.kt:18)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = BookService
│ args[1] = onCreate
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.BookService.onStartCommand(BookService.kt:22)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = BookService
│ args[1] = onStartCommand
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
从log可以看到,当使用startService()方式启动service时,service调用了onCreate 和 onStartCommand方法,service就被启动了。startservice的启动过程可以看这篇文章
然后我们再停止该service:
09-25 14:09:14.074 16466-16466/com.xyd.servicedemo I/BookService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.BookService.onDestroy(BookService.kt:28)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = BookService
│ args[1] = onDestroy
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
停止service调用的是:stopService(),当服务停止时,调用了service的onDestroy方法。
通过上边的例子可以看到通过startservice启动的service的生命周期,可以通过相应的方法管理service,并且启动的service不依赖与启动它的Activity,如果当前activity销毁,service也不会被销毁,还是会在后台运行,感兴趣的朋友可以试试。
创建同上:具体步骤不写了,直接上代码吧!
service代码:
class MovieService : Service(){
private val TAG = "MovieService"
private var movieBinder = MovieService.MovieBinder(this@MovieService)
private var isRun: Boolean = true
var count: Int = 0
var movieName: String = ""
private lateinit var myThread: Thread
override fun onCreate() {
super.onCreate()
LogUtils.i(TAG,"onBind")
myThread = object : Thread() {
override fun run() {
println("running from Thread: ${Thread.currentThread()}")
while (isRun){
try {
Thread.sleep(2000)
} catch (e: Exception) {
}
count++
movieName = "复仇者联盟$count"
println(movieName)
}
}
}
myThread.start()
}
override fun onBind(p0: Intent?): IBinder {
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
LogUtils.i(TAG,"onBind")
return movieBinder
}
class MovieBinder(private val movieService: MovieService) : Binder(){
val TAG = "MovieBinder"
fun getMovieService() : MovieService{
LogUtils.i(TAG,"getMovieService")
return movieService
}
}
override fun unbindService(conn: ServiceConnection?) {
super.unbindService(conn)
LogUtils.i(TAG,"unbindService")
}
override fun onDestroy() {
super.onDestroy()
isRun = false
LogUtils.i(TAG,"onDestroy")
}
}
activity代码已在上个例子中贴出,请查看。需要注意的是,与startservice方式不同的是,bindservice时需要创建一个ServiceConnection的实例,在bindservice时传递给service,该实例的作用是客户端与服务端通讯的媒介,具体可看一下这篇文章
运行:直接点击“绑定service”按钮,查看log:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.MovieService.onBind(MovieService.kt:45)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = MovieService
│ args[1] = onBind
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-25 14:32:52.109 16821-18011/com.xyd.servicedemo I/System.out: running from Thread: Thread[Thread-4,5,main]
09-25 14:32:52.109 16821-16821/com.xyd.servicedemo I/MainActivity:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.MainActivity.onServiceConnected(MainActivity.kt:52)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = MainActivity
│ args[1] = onServiceConnected
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-25 14:32:52.110 16821-16821/com.xyd.servicedemo I/MovieService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.MovieService$MovieBinder.getMovieService(MovieService.kt:53)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = MovieBinder
│ args[1] = getMovieService
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
通过bindservice后,服务启动,并且在客户端的ServiceConnection中回掉了onServiceConnected()方法,表示客户端已与服务端建立了连接,此时客户端是可以和服务端单向通讯的。如果是绑定状态的service,是依赖于启动它的activity的,当该activity销毁后,绑定的service也会被销毁。
接下来看一下客户端与服务端的通讯:
实例:客户端的代码一贴出,下边看一下服务端的代码
/**
* Created by zejian
* Time 2016/10/3.
* Description:Messenger服务端简单实例,服务端进程
*/
//此变量定义在类外部就可以被全包访问
val SEND_MESSAGE_CODE : Int = 0x0001
//服务端的消息处理
class InComingHandler : Handler(){
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
if (msg != null) {
when (msg.what) {
SEND_MESSAGE_CODE -> {
LogUtils.i("接受到客户端消息:" + msg.obj)
//接受完客户端的消息后需要返回给客户端消息
//通过msg.replyTo 方法 获取客户端的messenger
val clientMessenger = msg.replyTo
//获取到messenger之后,在通过客户端的messenger给客户端发送消息
val msg = Message.obtain()
msg.what = RECEIVE_MESSAGE_CODE
msg.obj = "hello client!!!"
Thread.sleep(3000)
clientMessenger.send(msg)
}
else -> {
LogUtils.i("未接受到客户端消息")
}
}
}
}
}
private val mMessenger = Messenger(InComingHandler())
class MusicService : Service(){
override fun onBind(p0: Intent?): IBinder? {
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
return mMessenger.binder
}
}
主要的处理逻辑已在代码中标明,请自行查看。
下面解决几个问题:
首先第一个问题:
- Service的start和bind状态的区别:首先是启动方式不同,start是直接启动,而bind是依赖于组件启动的,其次是启动的生命周期不同,start启动时执行的是onCreate
、onStartCommand的方法,而bind启动执行的是onBind方法。最后是start方式启动的service可以独立于组件运行,组件销毁之后,service不会停止运行,而bind方式启动的service则是依附于组件,组件销毁后,service会被强制停止运行。
class StartAndBindService : Service() {
val TAG = "StartAndBindService"
override fun onBind(intent: Intent): IBinder? {
LogUtils.i(TAG,"onBind")
return null
}
override fun onCreate() {
super.onCreate()
LogUtils.i(TAG,"onCreate")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
LogUtils.i(TAG,"onStartCommand")
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
LogUtils.i(TAG,"onDestroy")
}
}
然后在activity中新建两个按钮并设置点击事件,一个按钮是start,一个按钮是bind,运行之后,先点击start,然后点击bind,会出现以下结果:
09-26 12:59:55.249 4898-4898/com.xyd.servicedemo I/StartAndBindService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onCreate(StartAndBindService.kt:19)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onCreate
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-26 12:59:55.255 4898-4898/com.xyd.servicedemo I/StartAndBindService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onStartCommand(StartAndBindService.kt:23)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onStartCommand
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-26 12:59:57.826 4898-4898/com.xyd.servicedemo I/StartAndBindService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onBind(StartAndBindService.kt:13)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onBind
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
3、你有注意到Service的onStartCommand方法的返回值吗?不同返回值有什么区别?
这个问题可以看这篇文章,这个反之没有研究过
4、Service的生命周期方法onCreate、onStart、onBind等运行在哪个线程?
这个可以在service中打log查看,咱们来看看:
09-26 13:34:43.271 5937-5937/com.xyd.servicedemo I/StartAndBindService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onCreate(StartAndBindService.kt:25)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onCreate运行在主线程
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-26 13:34:43.273 5937-5937/com.xyd.servicedemo I/StartAndBindService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onStartCommand(StartAndBindService.kt:41)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onStartCommand运行在主线程
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onStart(StartAndBindService.kt:34)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onStart运行在主线程
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
09-26 13:34:47.690 5937-5937/com.xyd.servicedemo I/StartAndBindService:
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ main, com.xyd.servicedemo.services.StartAndBindService.onDestroy(StartAndBindService.kt:51)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│ args[0] = StartAndBindService
│ args[1] = onDestroy运行在主线程
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────
具体使用的判断为:Looper.getMainLooper() == Looper.myLooper()
demo地址