網站首頁 編程語言 正文
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 }
startService
和stopService
都定義在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()方法得到執行
原文鏈接:https://blog.csdn.net/change_fate/article/details/128784958
相關推薦
- 2022-11-14 C#中的委托、事件與接口
- 2022-07-24 .Net行為型設計模式之職責鏈模式(Chain?of?Responsibility)_基礎應用
- 2023-01-30 PyQt中使用QProcess運行一個進程的示例代碼_python
- 2022-05-12 tp5使用阿里云oss存儲圖片
- 2023-03-28 深入了解Android中GestureDetector的定義與使用_Android
- 2023-03-27 使用seaborn繪制強化學習中的圖片問題_python
- 2022-09-24 如何將一個CSV格式的文件分割成兩個CSV文件_python
- 2023-07-14 express token的一個用法
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支