Service的使用
1异步通信方式
Android在运行过程中所有程序都是主线程中执行的,因此当使用thread代码块实现一些组件的更新时,需要用到异步通信Handler。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.service_test_main)
//实现异步通信的方式进行更新数据
val handler=object : Handler(Looper.getMainLooper()){
override fun handleMessage(msg: Message) {
when(msg.what){
1->textView.text="师者所以传道授业解惑也"
}
}
}
//如果想在子线程里面进行组件的更新,需要使用到异步机制
change_textView.setOnClickListener(){
thread {
val msg=Message()
//更新文字
msg.what=1
handler.sendMessage(msg)
}
}
}
使用步骤:1创建handler对象,在里面重写handlerMessage方法用来处理消息到达之后的逻辑。2建立消息Message对象,并且绑定发送消息的类别,让其能够区别不同逻辑的处理方式。3handler来发送消息
2Service的启动和停止
1在MyService中继承Service,实现其中的方法即可获得自定义的Service,主要有如onBinder的以下几个方法
//此方法用来和Activity进行通信使用
override fun onBind(intent: Intent): IBinder {
return mBinder
}
//只有第一次调用的时候才会执行
override fun onCreate() {
super.onCreate()
}
//每次启动时都会调用
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
}
在Activity中启动时和Activity的启动方式类似
start_service.setOnClickListener(){
val intent= Intent(this,MyService::class.java)
startService(intent)
}
end_service.setOnClickListener(){
val intent=Intent(this,MyService::class.java)
stopService(intent)
}
3希望Activity和Service进行通信,让Activity知道Service在干什么事情或者进度如何。需要使用Service中的onBind()方法。
1在service中继承Binder()类,在此类中进行逻辑的编写,将结果通过onBind()方法返回
class MyService : Service() {
//为了实现和Activity的通信,模拟开启服务来进行下载功能
private val mBinder=DownloadBinder()
class DownloadBinder: Binder(){
fun startDownload(){
Log.d("MyService","开始下载")
}
fun getProgress():Int{
Log.d("MyService","当前下载的进度")
return 20
}
}
//此方法用来和Activity进行通信使用
override fun onBind(intent: Intent): IBinder {
return mBinder
}
//只有第一次调用的时候才会执行
override fun onCreate() {
super.onCreate()
}
//每次启动时都会调用
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
}
}
2在Activity中需要先对Activity和Service进行绑定,先实现ServiceConnection接口中的方法然后在方法里进行绑定之后的逻辑操作和解绑之后的逻辑操作。
class ServiceTest:AppCompatActivity() {
lateinit var downBinder:MyService.DownloadBinder
private val connnection=object :ServiceConnection{
//该方法会在Activity与Service绑定之后进行调用
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
downBinder=service as MyService.DownloadBinder
downBinder.startDownload()
downBinder.getProgress()
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.d("serviceTest","Service和Activity解绑成功")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.service_test_main)
//实现异步通信的方式进行更新数据
val handler=object : Handler(Looper.getMainLooper()){
override fun handleMessage(msg: Message) {
when(msg.what){
1->textView.text="师者所以传道授业解惑也"
}
}
}
//如果想在子线程里面进行组件的更新,需要使用到异步机制
change_textView.setOnClickListener(){
thread {
val msg=Message()
//更新文字
msg.what=1
handler.sendMessage(msg)
}
}
//service的启动和停止
start_service.setOnClickListener(){
val intent= Intent(this,MyService::class.java)
startService(intent)
}
end_service.setOnClickListener(){
val intent=Intent(this,MyService::class.java)
stopService(intent)
}
//数据和Service进行通信,获取到service的正在做的事情,需要对Service进行绑定
bind_service.setOnClickListener(){
val intent=Intent(this,MyService::class.java)
bindService(intent,connnection, Context.BIND_AUTO_CREATE)//绑定service
}
unBind_service.setOnClickListener(){
unbindService(connnection)
}
}
4实现前台的Service
在主Activity中点击按钮就启动当前的Service在前台通知上
class ForegroundServiceTest : Service() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate() {
super.onCreate()
val manager=getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel=NotificationChannel("myService","前台Service通知",NotificationManager.IMPORTANCE_DEFAULT)
manager.createNotificationChannel(channel)
val intent=Intent(this,ServiceTest::class.java)
val pi=PendingIntent.getActivity(this,0,intent,0)
val notification=NotificationCompat.Builder(this,"myService")
.setContentTitle("前台Service主题")
.setContentText("前台的Service的内容")
.setSmallIcon(R.drawable.ic_baseline_arrow_back_ios_24)
.setLargeIcon(BitmapFactory.decodeResource(resources,R.drawable.ic_baseline_menu_24))
.setContentIntent(pi)
.build()
startForeground(1,notification)
}
override fun onBind(intent: Intent): IBinder {
TODO("Return the communication channel to the service.")
}
}
5在Service中执行任务时更加规范的操作
一般在Service中可能需要进行比较耗时的操作,而主线程又需要获得结果,但是当长时间没有获得结果之后就会出现ANR(Application Not Responding)的情况,因此为了解决这种情况更标准的写法是在Service中创建新的线程来处理任务进行异步的工作。
//每次启动时都会调用
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
thread{
//在里面进行逻辑的处理工作,最后别忘了进行关闭
stopSelf()
}
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
super.onDestroy()
}