目录
Serivce基础
什么是Service ?
Android四大组件之一。
Service并不与用户产生UI交互。其他的应用组件可以启动Service,即便用户切换了其他应用,启动的Service仍可在后台运行。一个组件可以与Service绑定并与之交互,甚至是跨进程通信(IPC)。
基础使用
基础使用
有两种方式: startService() 和 bindService()
startService()方法启动一个Service
import android.app.Service
import android.content.Intent
import android.os.*
import android.util.Log
import android.widget.Toast
class HelloService : Service() {
private var mServiceLooper: Looper? = null
private var mServiceHandler: ServiceHandler? = null
companion object {
const val TAG = "HelloService"
}
private inner class ServiceHandler(looper: Looper) : Handler(looper) {
override fun handleMessage(msg: Message) {
Log.d(TAG, "handleMessage")
try {
Thread.sleep(5000)
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
}
}
}
override fun onCreate() {
Log.d(TAG, "onCreate")
val thread = HandlerThread(
"ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND
)
thread.start()
mServiceLooper = thread.looper
mServiceHandler = ServiceHandler(mServiceLooper!!)
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Log.d(TAG, "onStartCommand")
val msg: Message? = mServiceHandler?.obtainMessage()
msg?.arg1 = startId
msg?.let {
mServiceHandler?.sendMessage(msg)
}
return START_STICKY
}
override fun onBind(intent: Intent): IBinder? {
Log.d(TAG, "onBind")
return null
}
override fun onDestroy() {
Log.d(TAG, "onDestroy")
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show()
}
}
要在mainifest注册
<service
android:name="composer.service.HelloService"
android:exported="true"
android:enabled="true" />
activity中使用:
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import composer.databinding.ActivityTestStartServiceBinding
import composer.service.HelloService
import kotlinx.android.synthetic.main.activity_test_start_service.*
class TestStartServiceActivity : AppCompatActivity() {
lateinit var binding: ActivityTestStartServiceBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTestStartServiceBinding.inflate(LayoutInflater.from(this))
setContentView(binding.root)
startMyService.setOnClickListener {
val intent = Intent(baseContext, HelloService::class.java)
startService(intent)
}
stopMyService.setOnClickListener {
val intent = Intent(baseContext, HelloService::class.java)
stopService(intent)
}
}
}
运行打出的日志:
onCreate ---> onStartCommand ---> handleMessage ---> onDestory
bindService()方法绑定一个Service
import android.app.Service
import android.content.Intent
import android.os.*
import android.util.Log
import android.widget.Toast
class HelloService : Service() {
private var mServiceLooper: Looper? = null
private var mServiceHandler: ServiceHandler? = null
private val countNumBinder = CountNumBinder()
companion object {
const val TAG = "HelloService"
}
inner class CountNumBinder: Binder() {
fun getCount(): Int {
Log.i(TAG, ">>>>>>getCount()");
return 100;
}
}
private inner class ServiceHandler(looper: Looper) : Handler(looper) {
override fun handleMessage(msg: Message) {
Log.d(TAG, "handleMessage")
try {
Thread.sleep(5000)
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
}
}
}
override fun onCreate() {
Log.d(TAG, "onCreate")
val thread = HandlerThread(
"ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND
)
thread.start()
mServiceLooper = thread.looper
mServiceHandler = ServiceHandler(mServiceLooper!!)
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Log.d(TAG, "onStartCommand")
val msg: Message? = mServiceHandler?.obtainMessage()
msg?.arg1 = startId
msg?.let {
mServiceHandler?.sendMessage(msg)
}
return START_STICKY
}
override fun onBind(intent: Intent): IBinder {
Log.d(TAG, "onBind")
return countNumBinder
}
override fun onDestroy() {
Log.d(TAG, "onDestroy")
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show()
}
}
activity中使用:
package composer.view
import android.app.Service
import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import composer.databinding.ActivityTestStartServiceBinding
import composer.service.HelloService
import kotlinx.android.synthetic.main.activity_test_start_service.*
class TestStartServiceActivity : AppCompatActivity() {
lateinit var binding: ActivityTestStartServiceBinding
var countNumBinder: HelloService.CountNumBinder? = null
companion object {
const val TAG = "HelloService activity"
}
private val conn = object: ServiceConnection {
// Activity与Service断开连接时回调该方法
@Override
override fun onServiceDisconnected(name: ComponentName) {
Log.d(TAG, ">>>>>>Service DisConnected");
}
//Activity与Service连接成功时回调该方法
@Override
override fun onServiceConnected(name: ComponentName, service: IBinder) {
Log.i(TAG, ">>>>>>Service Connected");
countNumBinder = service as HelloService.CountNumBinder
Log.i(TAG, ">>>>>>Service Connected: " + countNumBinder?.getCount());
}}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTestStartServiceBinding.inflate(LayoutInflater.from(this))
setContentView(binding.root)
startMyService.setOnClickListener {
val intent = Intent(baseContext, HelloService::class.java)
startService(intent)
}
stopMyService.setOnClickListener {
val intent = Intent(baseContext, HelloService::class.java)
stopService(intent)
}
bindMyService.setOnClickListener {
val intent = Intent(baseContext, HelloService::class.java)
bindService(intent, conn, Service.BIND_AUTO_CREATE)
}
}
}
运行打出的日志:
onCreate ---> onBind ---> Service Connected ---> getCount() ---> Service Connected : 100
startService和bindService异同
生命周期
- startService方式:
可以多次调用,但是onCreate()只执行一遍,也就是Service只会创建一次,每次调用onStartCommand都会被调用。
该方式Service的生命周期为onCreate()
-> onStartCommand
…onDestroy
。
- bindService方式:
只有第一次调用会创建Service,执行onCreate()和onBind(),连续多次调用并不会执行onCreate()和onBind();
onCreate()
->onBind()
…onUnBind
独立性
- startService方式:
Service一旦被启动,在调用者没有调用stopService()的前提下,其生命周期就和调用者的生命周期不再关联。即使调用者被杀掉,Service也可以独立生存。
- bindService方式:
与startService方式不同的是,这种方式,service的生命周期是和调用者关联在一起的,如果调用者进程被终结后,服务便会终止。
交互方式
- startService之后可以发送action与服务交互。
- bindService之后,除了发送action还 可以获得服务的完整方法(Binder的实现类),可以直接交互;
总结
startservice启动服务后,程序退出stopservice,服务依旧存在。
而bindservice启动服务后程序退出unbindservice,服务就会销毁。
而同时调用两种方法启动同一个方法,只会启动一个服务,但是其生命周期有所不同,取决于两种方法启动服务的先后顺序。
=========================================================================
tartService和bindService混合使用
tips:
bindService与startService同时执行创建的是同一个Service实例,因为onCreate只执行了一次。
用bindService+startService的方式可以同时享受两者的优点,可以持久后台运行并且可以通过调用者操作Service。
场景1:
startService bindService & unbindServiced stopService
生命周期:
onCreate – onStartCommand – onBind – onUnbind–onDestroy
开始 --- > 运行startService,bindService开启服务
结束 --- > 运行unbindServiced,stopService结束服务
场景2:
startService bindSErvice & 销毁调用者(activity销毁等)
生命周期:
onCreate – onStartCommand – onBind – onUnbind(调用者销毁时)-- onDestroy(后台持续运行,直到被系统回收或者用户强制销毁服务)
这里 调用者销毁后,服务解绑,未销毁Service。
场景3:
bindService startService & unbindService stopService
生命周期:
onCreate – onBind – onStartCommand – onUnbind – onDestroy
bindService先运行,onBind将先与onStartCommand执行
结束 --》执行unbindService,stopService,正常销毁服务。
场景4:
bindService startService & 销毁调用者(activity销毁等)
生命周期:
onCreate – onBind – onStartCommand – onUnbind (销毁调用者时)-- onDestroy(后台持续运行,直到被系统回收或者用户强制销毁服务)
总结
用bindService+startService的方式可以同时享受两者的优点,可以持久后台运行并且可以通过调用者操作Service。
示例代码:
stopBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(myConnection);
stopService(serviceOne);
}
});
startBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(serviceOne,myConnection,BIND_AUTO_CREATE);
startService(serviceOne);
}
});