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