Kotlin server多線程編程詳細講解
service 是什么
Service是實現(xiàn)程序后臺運行的解決方案,適合執(zhí)行非交互,后臺預(yù)先的任務(wù),即使用戶打開其他應(yīng)用,Service也能夠正常運行
Service需要內(nèi)部手動創(chuàng)建子線程
多線程編程
用法:
(1) 繼承的方式(耦合較高,不推薦)
class MyThread : Thread() {
override fun run () {
// 編寫具體邏輯
}
}
// 啟動
MyThread().start()
(2) Runnable接口定義一個線程
class MyThread : Runnable {
override fun run () {
// 子線程具體邏輯
}
}
// 啟動
val myThread = MyThread()
Thread(myThread).start()
簡化寫法:如果你不想專門定義一個類去實現(xiàn)Runnable接口, 可以使用Lambda方式
Thread {
// 編寫具體邏輯
}.start()
更加簡化的寫法:
thread {
// 編寫具體的邏輯
}
在子線程中更新UI
Android 的UI 也是線程不安全的, 更新應(yīng)用程序的UI元素, 必須在主線程中進行, 否則會出現(xiàn)異常
如果在子線程中直接更新UI,會出現(xiàn)崩潰,提示如下錯誤
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攜帶整型數(shù)據(jù), obj字段攜帶Obejct對象
(2) Handler,用于發(fā)送和接收消息
發(fā)送: 使用sendMessage() post() 方法
接受: 最終會傳遞到handleMessage方法中
(3) MessageQueue, 消息隊列,存放Handler發(fā)送的消息,等待被處理,每個線程只會有一個MessageQueue
(4) Looper, 是每個線程中MessageQueue的管家, 調(diào)用Looper的 loop() 方法后,會進入無限循環(huán)中,每當發(fā)現(xiàn)MessageQueue中存在一條消息,就取出,并傳遞到Handler的handleMessage方法中,每個線程用一個Looper對象
異步消息處理流程:
1 主線程創(chuàng)建handler對象, 重寫handleMessage方法
2 當子線程中需要進行UI操作,就創(chuàng)建一個Message對象,通過Handler 的sandMessage方法將消息發(fā)送出去,消息被添加到MessageQueue中等待
3 Looper一直嘗試從MessageQueue中取消息,最后分發(fā)給Handler的handlerMessage方法中,由于Handler函數(shù)中傳入了Looper.getMainLooper(), 此時handleMessage() 方法中的代碼會在主線程中運行
4 使用AsyncTask
為了方便子線程對UI操作, Android提供了一些好用的工具如AsyncTask,原來也是基于異步消息處理
(1)基本用法:
AsyncTask是一個抽象類,如果想使用它,需要一個子類繼承,可以在繼承時指定3個泛型參數(shù): params: 可在后臺任務(wù)中使用 progress :在后臺任務(wù)執(zhí)行時, 如果需要在界面上顯示的進度,使用泛型作為進度單位 Result 任務(wù)執(zhí)行完后, 對結(jié)果進行返回, 返回泛型類型
最簡單的形式:
class DownloadTask :AsyncTask<Unit, Int, Boolean> () {
}
當前是一個空任務(wù),無任何實際操作,需要重寫4個方法:
1 onPreExecute() 在任務(wù)執(zhí)行前調(diào)用,用于初始化操作
2 doInBackground(Params…) 在子線程中執(zhí)行, 執(zhí)行具體耗時任務(wù)
3 onProgressUpdate(Progress…) 后臺任務(wù)調(diào)用,進行UI操作
4 onPostExecute(Result) 后臺任務(wù)執(zhí)行完畢并通過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唯一抽象方法,需要在子類實現(xiàn)
重寫一些方法:
- onCreate() service創(chuàng)建調(diào)用
- onStartCommand() 每次service啟動調(diào)用
- onDestory() 銷毀調(diào)用
ps: Service需要在AndroidManifest.xml文件中注冊(在創(chuàng)建service中會自動注冊)
啟動和停止Service
要借助Intent實現(xiàn),在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
}
startService和stopService 都定義在Context類中,可以直接調(diào)用
另外可以自我停止:
在service內(nèi)部調(diào)用stopSelf()方法
啟動后可以在: 應(yīng)用 -》顯示系統(tǒng)應(yīng)用 中找到
Android8.0后,應(yīng)用在前臺,service才能穩(wěn)定運行,否則隨時可能被系統(tǒng)回收
Activity 與 Service通信: onBind 方法
查看下載進度:,創(chuàng)建一個專門的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 綁定了之后,就可以調(diào)用該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個參數(shù)
第一個是Intent對象
第二個是ServiceConnection的實例
第三個是一個標志位 BIND_AUTO_CREATE 表示在Activity 和Service 進行綁定后
自動創(chuàng)建Service
這會使得MyService 中的onCreate()方法得到執(zhí)行
到此這篇關(guān)于Kotlin server多線程編程詳細講解的文章就介紹到這了,更多相關(guān)Kotlin server內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入淺析Android手機衛(wèi)士保存密碼時進行md5加密
一般的手機沒有root權(quán)限,進不去data/data目錄,當手機刷機了后,擁有root權(quán)限,就可以進入data/data目錄,查看我們保存的密碼文件,因此我們需要對存入的密碼進行MD5加密,接下來通過本文給大家介紹Android手機衛(wèi)士保存密碼時進行md5加密,需要的朋友一起學(xué)習(xí)吧2016-04-04
android中ProgressDialog與ProgressBar的使用詳解
本篇文章是對android中ProgressDialog與ProgressBar的使用進行了詳細的分析介紹,需要的朋友參考下2013-06-06
Android通過Handler與AsyncTask兩種方式動態(tài)更新ListView(附源碼)
這篇文章主要介紹了Android通過Handler與AsyncTask兩種方式動態(tài)更新ListView的方法,結(jié)合實例形式分析了ListView動態(tài)更新的常用技巧,并附上完整實例源碼供讀者下載,需要的朋友可以參考下2015-12-12
Android?Activity生命周期調(diào)用的理解
大家好。本篇文章主要講的是Android?Activity生命周期調(diào)用的理解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12
Android編程實現(xiàn)仿優(yōu)酷圓盤旋轉(zhuǎn)菜單效果的方法詳解【附demo源碼下載】
這篇文章主要介紹了Android編程實現(xiàn)仿優(yōu)酷圓盤旋轉(zhuǎn)菜單效果的方法,涉及Android界面布局及事件響應(yīng)相關(guān)操作技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2017-08-08
Android 手機瀏覽器調(diào)試使用Chrome進行調(diào)試實例詳解
這篇文章主要介紹了Android 手機瀏覽器調(diào)試使用Chrome進行調(diào)試實例詳解的相關(guān)資料,這里提供了實例,需要的朋友可以參考下2016-12-12
Android開發(fā)之設(shè)置開機自動啟動的幾種方法
這篇文章主要介紹了Android開發(fā)之設(shè)置開機自動啟動的幾種方法的相關(guān)資料,這里提供三種方法幫助大家實現(xiàn)這樣的功能,需要的朋友可以參考下2017-08-08

