运行 CountDownTimer 在 CoroutineWorker 内部。

huangapple go评论65阅读模式
英文:

Run CountDownTimer inside CoroutineWorker

问题

I am developing a registration form with Kotlin in Android and after several failed attempts I need to block the form for a while, be it an hour or 30 minutes, and let the service run in the background so the app closes or gets destroyed.

After consulting and reading the Android documentation, I am solving this problem with WorkManager by extending the CoroutineWorker() class, but I find the following problem that does not let me proceed:

无法在线程Thread[DefaultDispatcher-worker-1,5,main]内创建处理程序,尚未调用Looper.prepare()

调用CoroutineWorker的ViewModel

@HiltViewModel
class RegisterViewModel @Inject constructor(
private val registerUseCase: RegisterUseCase
) : ViewModel() {

fun makeApiPost(
    context: Context,
    card: String,
    .... : ...
) {

    viewModelScope.launch {
        val retroInstance = RetroInstance.getRetroInstanceAuth(context).create(
            RetroService::class.java
        )
        val call = retroInstance.getGiftCardBalance(
            CardBalanceRequest(card, ..., ...)
        )
        call.enqueue(object : Callback<BalanceResponse> {
            override fun onResponse(
                call: Call<BalanceResponse>,
                response: Response<AppBalanceResponse>
            ) {

                if (response.isSuccessful) {
                    val destination = response.body()
                    destination?.let {
                        _cardBalance.postValue(response.body()!!.payload.data)
                    }
                } else {

                    val workManager = WorkManager.getInstance(ExtendedApp.myContext)
                    workManager.enqueue(OneTimeWorkRequest.from(WorkerActivate::class.java))

                    _cardBalance.postValue(null)
                }

            }

            override fun onFailure(call: Call<CardBalanceResponse>, t: Throwable) {
                t.printStackTrace()
                _cardBalance.postValue(null)
                call.request()
            }
        })
    }
}

}

后台处理

class WorkerActivate(context: Context, workerParameters: WorkerParameters) : CoroutineWorker(
context, workerParameters
)
{

lateinit var countDownTimer: CountDownTimer

override suspend fun doWork(): Result {
    
    val minutesTimer: Long = (60 * 1000 * 30)

    countDownTimer = object : CountDownTimer(minutesTimer, 1000){
        override fun onTick(millisUntilFinished: Long) {
            Log.d("card", "Counting Down: ${millisUntilFinished/1000}")
        }

        override fun onFinish() {
            Log.i("card", "countDownTimer de 15 segundos ok")
        }
    }
    
    return Result.success()
    
}

}

英文:

I am developing a registration form with kotlin in android and after several failed attempts I need to block the form for a while, be it an hour or 30 minutes and that the service runs in the background so the app closes or destroys

After consulting and reading the android documentation, I am solving this problem with workmanager by extending the CoroutineWorker() class, but I find the following problem that does not let me proceed:

Can&#39;t create handler inside thread Thread[DefaultDispatcher-worker-1,5,main] that has not called Looper.prepare()

ViewModel that invokes the CoroutineWorker

    @HiltViewModel
class RegisterViewModel @Inject constructor(
    private val registerUseCase: RegisterUseCase
) : ViewModel() {
	
		fun makeApiPost(
				context: Context,
				card: String,
				.... : ...
			)
		{

			viewModelScope.launch {
				val retroInstance = RetroInstance.getRetroInstanceAuth(context).create(
					RetroService::class.java
				)
				val call = retroInstance.getGiftCardBalance(
					CardBalanceRequest(card, ..., ...)
				)
				call.enqueue(object : Callback&lt;BalanceResponse&gt; {
					override fun onResponse(
						call: Call&lt;BalanceResponse&gt;,
						response: Response&lt;AppBalanceResponse&gt;
					) {

						if (response.isSuccessful) {
							val destination = response.body()
							destination?.let {
								_cardBalance.postValue(response.body()!!.payload.data)
							}
						} else {

							val workManager = WorkManager.getInstance(ExtendedApp.myContext)
							workManager.enqueue(OneTimeWorkRequest.from(WorkerActivate::class.java))

							_cardBalance.postValue(null)
						}

					}

					override fun onFailure(call: Call&lt;CardBalanceResponse&gt;, t: Throwable) {
						t.printStackTrace()
						_cardBalance.postValue(null)
						call.request()
					}
				})
			}
		}
}

Background process

    class WorkerActivate(context: Context, workerParameters: WorkerParameters) : CoroutineWorker(
        context, workerParameters
    )
    {
    
        lateinit var countDownTimer: CountDownTimer
    
        override suspend fun doWork(): Result {
    		
            val minutesTimer: Long =  (60 * 1000 * 30)

    		countDownTimer =  object : CountDownTimer(minutesTimer, 1000){
    			override fun onTick(millisUntilFinished: Long) {
    				Log.d(&quot;card&quot;, &quot;Counting Down: ${millisUntilFinished/1000}&quot;)
    			}
    
    			override fun onFinish() {
    				Log.i(&quot;card&quot;, &quot;countDownTimer de 15 segundos ok&quot;)
    			}
    		}
    		
    		return Result.success()
    		
    	}
    }

答案1

得分: 2

在你的代码中,第13行有问题。WorkManager 只能从主线程启动,这就是你出现这个错误的原因。

viewModelScope.launch {
    &lt;&lt;&lt; 这个区域是子线程 &gt;&gt;&gt;
}

// 尝试这样做...
withContext(Dispatchers.Main) {
    val workManager = WorkManager.getInstance(ExtendedApp.myContext)
    workManager.enqueue(OneTimeWorkRequest.from(WorkerActivate::class.java))
}
英文:

in your code 13 line is the problem. WorkManager can only be started from the Main thread and that`s the reason you are getting this error.

viewModelScope.launch {
&lt;&lt;&lt; This area is sub Thread &gt;&gt;&gt;
}

// Try this...
withContext(Dispatchers.Main) {
    val workManager = WorkManager.getInstance(ExtendedApp.myContext)
    workManager.enqueue(OneTimeWorkRequest.from(WorkerActivate::class.java))
}

huangapple
  • 本文由 发表于 2023年4月11日 14:41:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75983051.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定