记录关于CoroutineScope.cancel()的问题。

在项目中遇到一个问题,在前台service执行逻辑时,在onStartCommand中使用serviceScope.launch {}前调用了serviceScope..cancel(),导致后续所有的launch都无效

后来发现serviceScope..cancel()取消的是当前作用域下的所有协程,不管是之前还是之后创建的

其中private val serviceScope = CoroutineScope(Dispatchers.IO + Job())

// src/main/java/com/example/whackamole/MainActivity.kt package com.example.whackamole import android.os.Bundle import android.view.View import android.widget.ImageView import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import kotlinx.coroutines.* import kotlin.random.Random class MainActivity : AppCompatActivity() { // 游戏参数 private lateinit var mouse: ImageView private lateinit var scoreText: TextView private lateinit var timerText: TextView private var score = 0 private var timeLeft = 60 private var gameActive = true // 洞穴位置(相对坐标,会自动适配屏幕) private val holePositions = listOf( Pair(0.25f, 0.15f), Pair(0.45f, 0.15f), Pair(0.65f, 0.15f), Pair(0.85f, 0.15f), Pair(0.25f, 0.35f), Pair(0.45f, 0.35f), Pair(0.65f, 0.35f), Pair(0.85f, 0.35f), Pair(0.25f, 0.65f), Pair(0.45f, 0.65f), Pair(0.65f, 0.65f), Pair(0.85f, 0.65f) ) // 协程作用域 private val coroutineScope = CoroutineScope(Dispatchers.Main) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 设置全屏和横屏 supportActionBar?.hide() window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN // 绑定UI元素 mouse = findViewById(R.id.mouse) scoreText = findViewById(R.id.scoreText) timerText = findViewById(R.id.timerText) // 设置点击事件 mouse.setOnClickListener { if (gameActive && mouse.visibility == View.VISIBLE) { score++ scoreText.text = "Score: $score" mouse.visibility = View.INVISIBLE // 播放音效 (需要添加音效文件) // MediaPlayer.create(this, R.raw.hit).start() } } // 启动游戏 startGame() } private fun startGame() { // 启动计时器 coroutineScope.launch { while (timeLeft > 0 && gameActive) { delay(1000) timeLeft-- timerText.text = "Time: $timeLeft" } if (gameActive) { gameActive = false Toast.makeText( this@MainActivity, "游戏结束! 得分: $score", Toast.LENGTH_LONG ).show() } } // 启动地鼠生成器 coroutineScope.launch { while (gameActive) { delay(Random.nextLong(500, 1500)) // 随机延迟 showMouse() } } } private fun showMouse() { if (!gameActive) return // 随机选择一个洞穴 val (xPercent, yPercent) = holePositions.random() // 计算实际位置(适配不同屏幕) val layout = findViewById<View>(R.id.gameLayout) val xPos = xPercent * layout.width - mouse.width / 2 val yPos = yPercent * layout.height - mouse.height / 2 // 显示地鼠 mouse.x = xPos mouse.y = yPos mouse.visibility = View.VISIBLE // 设置自动消失(2秒后) coroutineScope.launch { delay(2000) if (mouse.visibility == View.VISIBLE) { mouse.visibility = View.INVISIBLE } } } override fun onDestroy() { super.onDestroy() gameActive = false coroutineScope.cancel() } } 可是我的包名字是playmouse
11-13
class JAFRSHS99100P001Service @Inject constructor( private val localStorageRepository: LocalStorageRepository, private val jAFRSHS99300P007UseCase: IJAFRSHS99300P007UseCase, private val activity: ComponentActivity ) : BroadcastReceiver() { private val serviceJob = Job() private val coroutineScope = CoroutineScope(Dispatchers.IO) // 遅延初期化によるActivityResultLauncher private var movementInfoLauncher: ActivityResultLauncher<Intent> // リクエスト成功フラグ private var requestSuccess = false init { // ActivityResultレジストラの初期化 movementInfoLauncher = activity.registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> // 結果受信時の処理 result.data?.let { data -> // アクションと結果値の検証 if (data.action == "com.nec.jp.car.syg" + "ACTION_REQUEST_MOVEMENT_INFO" ) { if (result.data?.getIntExtra("result", -1) == 0) { // 成功フラグ設定 requestSuccess = true } } } } } /** * 車載ナビ連携初期処理 */ suspend fun invoke() { try { // 車載ナビ位置取得タイマー値 val timmer: Long = localStorageRepository.getMCarWorkSettingInfoList().find { it.parameterName == "車載ナビ位置取得タイマー値" }?.parameterValue?.toLong() ?: 30000L // 受信キュー定期チェック間隔ごとに処理が開始される coroutineScope.launch { // 車載ナビに車両位置情報要求を通知する val intentTmp: Intent = Intent( "com.nec.jp.car.syg" + "ACTION_REQUEST_MOVEMENT_INFO" ) .apply { putExtra("send_mode", 1) putExtra("send_interval", timmer) } val context: Context = localStorageRepository.getContext() context.startActivity(intentTmp) // 車載ナビに通知が失敗した場合、10秒後に再度、車両位置情報要求を通知する while (true) { // 成功フラグをリセット requestSuccess = false // アクティビティランチャー経由でリクエスト送信 movementInfoLauncher.launch(intentTmp) delay(10000) if (requestSuccess) { // 成功時はループ終了 break } } } } catch (ex: Exception) { throw ex } } /** * 車載ナビ位置情報受信処理 */ override fun onReceive(context: Context?, intent: Intent?) { try { if (intent?.action == "com.nec.jp.car.syg" + "ACTION_NOTIFY_MOVEMENT_INFO") { coroutineScope.launch { jAFRSHS99300P007UseCase(intent).getOrThrow() } } } catch (ex: Exception) { throw ex } } } 我想在循环之前的启动Activity,循环里先判断,再重新通知
09-23
class JAFRSHS99100P001ServiceImpl @Inject constructor( /** 車載ナビ位置情報受信処理UseCase */ private val jAFRSHS99300P007UseCase: JAFRSHS99300P007UseCase, /** ローカルストレージ */ private val localStorage: LocalStorage, ) : BroadcastReceiver() { /** コンポーネントアクティビティ参照 */ private var activity: ComponentActivity = ComponentActivity() /** サービスジョブ */ private var serviceJob = Job() /** コルーチンスコープ(IOディスパッチャ + サービスジョブ) */ private var coroutineScope = CoroutineScope(Dispatchers.IO + serviceJob) /** 遅延初期化によるActivityResultLauncher - 移動情報取得用 */ private var movementInfoLauncher: ActivityResultLauncher<Intent> /** リクエスト成功フラグ */ private var requestSuccess = false init { // ActivityResultレジストラの初期化 movementInfoLauncher = activity.registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> // 結果受信時の処理 result.data?.let { data -> // アクションと結果値の検証 if (data.action == Navi.ACTION_REQUEST_MOVEMENT_INFO.value ) { if (result.data?.getIntExtra("result", -1) == 0) { // 成功フラグ設定 requestSuccess = true } } } } } /** * 車載ナビ連携初期処理 */ suspend fun invoke() { try { // 設定値を取得する。 val timmer = localStorage.getMCarWorkSettingInfoList().find { it.parameterName == MCarWorkSettingInfoEnum.CarNaviGpsGetTime.code }?.parameterValue?.toLong() ?: 30000L // 受信キュー定期チェック間隔ごとに処理が開始される coroutineScope.launch { // 車載ナビに車両位置情報要求を通知する val intentTmp = Intent( Navi.ACTION_REQUEST_MOVEMENT_INFO.value ) .apply { putExtra("send_mode", 1) putExtra("send_interval", timmer) } movementInfoLauncher.launch(intentTmp) // 車載ナビに通知が失敗した場合、10秒後に再度、車両位置情報要求を通知する delay(10000) while (isActive) { if (requestSuccess) { // 成功時はループ終了 break } // アクティビティランチャー経由でリクエスト送信 movementInfoLauncher.launch(intentTmp) delay(10000) } } } catch (ex: Exception) { val sendBroadcastTmp = SendBroadcast<List<String>>( processingID = WebProcessingID.JAFRSHO99020E001.id, screenID = null, message = ex.message, item = listOf() ) // ブロードキャストの発行して各画面に関連処理を行う。 AndroidBroadcastSender.sendBroadcast(sendBroadcastTmp) } } /** * 車載ナビ位置情報受信処理 * * @param contextParam コンテキスト * @param intentParam インテント */ override fun onReceive(contextParam: Context?, intentParam: Intent?) { try { if (intentParam?.action == Navi.ACTION_NOTIFY_MOVEMENT_INFO.value) { coroutineScope.launch { jAFRSHS99300P007UseCase(intentParam).getOrThrow() } } } catch (ex: Exception) { // すべての画面へブロードキャスト発行を設定する。 val sendBroadcastTmp = SendBroadcast<List<String>>( processingID = WebProcessingID.JAFRSHO99020E001.id, screenID = null, message = ex.message, item = listOf() ) // ブロードキャストの発行して各画面に関連処理を行う。 AndroidBroadcastSender.sendBroadcast(sendBroadcastTmp) } } /** * リソースクリーンアップ */ fun onDestroy() { serviceJob.cancel() } }如何启动该Service 以及有什么隐患这段代码
最新发布
12-02
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值