Kotlin server多线程编程详细讲解

service 是什么

Service是实现程序后台运行的解决方案,适合执行非交互,后台预先的任务,即使用户打开其他应用,Service也能够正常运行

Service需要内部手动创建子线程

多线程编程

用法:

(1) 继承的方式(耦合较高,不推荐)

class MyThread : Thread() {
 override fun run () {
 // 编写具体逻辑
 }
}
// 启动
MyThread().start()

(2) Runnable接口定义一个线程

class MyThread : Runnable {
 override fun run () {
 // 子线程具体逻辑
 }
}
// 启动
val myThread = MyThread()
Thread(myThread).start()

简化写法:如果你不想专门定义一个类去实现Runnable接口, 可以使用Lambda方式

Thread {
 // 编写具体逻辑
}.start()

更加简化的写法:

thread {
 // 编写具体的逻辑
}

在子线程中更新UI

Android 的UI 也是线程不安全的, 更新应用程序的UI元素, 必须在主线程中进行, 否则会出现异常
如果在子线程中直接更新UI,会出现崩溃,提示如下错误

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

那子线程如何更新UI呢?

通过异步消息传递给主线程, 在主线程更新UI 修改MainActivity.kt

class MainActivity : AppCompatActivity() {
 val sign = 1
 val handler = object: Handler(Looper.getMainLooper()) {
 override fun handleMessage(msg: Message) {
 when (msg.what) {
 sign -> textView.text = "Nice to meet you 2"
 }
 }
 }
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 button.setOnClickListener{
 thread {
 val msg = Message()
 msg.what = sign
 handler.sendMessage(msg)
 }
 }
 }
}

定义一个Handler对象,重写handleMessage方法

如果Message(android.os.Message)的what字段等于sign,就将UI更新

异步消息处理机制

(1) Message 线程中传递少量消息,使用arg1和arg2携带整型数据, obj字段携带Obejct对象

(2) Handler,用于发送和接收消息

发送: 使用sendMessage() post() 方法

接受: 最终会传递到handleMessage方法中

(3) MessageQueue, 消息队列,存放Handler发送的消息,等待被处理,每个线程只会有一个MessageQueue

(4) Looper, 是每个线程中MessageQueue的管家, 调用Looper的 loop() 方法后,会进入无限循环中,每当发现MessageQueue中存在一条消息,就取出,并传递到Handler的handleMessage方法中,每个线程用一个Looper对象

异步消息处理流程:

1 主线程创建handler对象, 重写handleMessage方法

2 当子线程中需要进行UI操作,就创建一个Message对象,通过Handler 的sandMessage方法将消息发送出去,消息被添加到MessageQueue中等待

3 Looper一直尝试从MessageQueue中取消息,最后分发给Handler的handlerMessage方法中,由于Handler函数中传入了Looper.getMainLooper(), 此时handleMessage() 方法中的代码会在主线程中运行

4 使用AsyncTask

为了方便子线程对UI操作, Android提供了一些好用的工具如AsyncTask,原来也是基于异步消息处理

(1)基本用法:

AsyncTask是一个抽象类,如果想使用它,需要一个子类继承,可以在继承时指定3个泛型参数: params: 可在后台任务中使用 progress :在后台任务执行时, 如果需要在界面上显示的进度,使用泛型作为进度单位 Result 任务执行完后, 对结果进行返回, 返回泛型类型

最简单的形式:

class DownloadTask :AsyncTask<Unit, Int, Boolean> () {
}

当前是一个空任务,无任何实际操作,需要重写4个方法:

1 onPreExecute() 在任务执行前调用,用于初始化操作

2 doInBackground(Params…) 在子线程中执行, 执行具体耗时任务

3 onProgressUpdate(Progress…) 后台任务调用,进行UI操作

4 onPostExecute(Result) 后台任务执行完毕并通过return返回时, 收尾工作

Service 基本用法

1.定义一个Service

新建一个ServiceTest项目

右击 com.example.servicetest -> New -> Service -> Service

类名改成MyService, Exported表示将Service暴露给外部访问

Enable表示启用这个Service

生成如下代码:

class MyService : Service() { 
 override fun onBind(intent: Intent): IBinder { 
 TODO("Return the communication channel to the service.")
 } 
}

MyService 继承自Service类, 有一个onBind方法,是Service唯一抽象方法,需要在子类实现

重写一些方法:

  • onCreate() service创建调用
  • onStartCommand() 每次service启动调用
  • onDestory() 销毁调用

ps: Service需要在AndroidManifest.xml文件中注册(在创建service中会自动注册)

启动和停止Service

要借助Intent实现,在ServiceTest中启动停止MyService

添加两个按钮:

startServiceBtn.setOnClickListener { 
 val intent = Intent(this, MyService::class.java) 
 startService(intent) // 启动Service 
 } 
 stopServiceBtn.setOnClickListener { 
 val intent = Intent(this, MyService::class.java) 
 stopService(intent) // 停止Service 
 }

startServicestopService 都定义在Context类中,可以直接调用

另外可以自我停止:

在service内部调用stopSelf()方法

启动后可以在: 应用 -》显示系统应用 中找到

Android8.0后,应用在前台,service才能稳定运行,否则随时可能被系统回收

Activity 与 Service通信: onBind 方法

查看下载进度:,创建一个专门的Binder对象管理下载功能:

private val mBinder = DownloadBinder()
class DownloadBinder : Binder() {
 fun startDownload() {
 Log.d("MyService", "startDownload executed")
 }
 fun getProgress(): Int{
 Log.d("MyService", "getProgress executed")
 return 0
 }
}
override fun onBind(intent: Intent): IBinder {
 return mBinder
}

当一个Activity 和Service 绑定了之后,就可以调用该Service 里的Binder提供的方法了。

在activity中,修改:

lateinit var downloadBinder: MyService.DownloadBinder
private val connection = object : ServiceConnection {
	override fun onServiceConnected(name: ComponentName, service: IBinder) {
	 downloadBinder = service as MyService.DownloadBinder
	 downloadBinder.startDownload() 
	 downloadBinder.getProgress() 
	} 
	override fun onServiceDisconnected(name: ComponentName) {
	} 
}
...
// 绑定service
bindServiceBtn.setOnClickListener { 
	val intent = Intent(this, MyService::class.java) 
	bindService(intent, connection, Context.BIND_AUTO_CREATE) // 绑定Service 
}
// 解绑service
unbindServiceBtn.setOnClickListener { 
 unbindService(connection) // 解绑Service 
}

bindService()方法接收3个参数

第一个是Intent对象
第二个是ServiceConnection的实例
第三个是一个标志位 BIND_AUTO_CREATE 表示在Activity 和Service 进行绑定后
自动创建Service
这会使得MyService 中的onCreate()方法得到执行

作者:change_fate原文地址:https://blog.csdn.net/change_fate/article/details/128784958

%s 个评论

要回复文章请先登录注册