我正试图创建一个tabata计时器。我设法从editText中获取用户输入,并启动一个计时器,它表示准备时间。
当准备时间结束后,我想开始工作时间,然后是Rest时间。稍后,当用户输入时,我需要将Worktime和Resttime重复x次。但我想不通。
MainActivity.kt:
btn_Start_Timer.setOnClickListener() {
val prepTimeMillis = Integer.parseInt(eT_PrepTime.text.toString().trim()) * 1000L;
val workTimeMillis = Integer.parseInt(eT_PrepTime.text.toString().trim()) * 1000L;
val restTimeMillis = Integer.parseInt(eT_PrepTime.text.toString().trim()) * 1000L;
val numberOfRepetitions = Integer.parseInt(eT_Number_Repetitions.text.toString().trim());
val Timer = object : CountDownTimer(prepTimeMillis, 1000) {
override fun onTick(millisUntilFinished: Long) {
tV_Total_Duration.setText("Preparation 00:00: " + millisUntilFinished / 1000)
}
override fun onFinish() {
tV_Total_Duration.setText("Preparation done!")
}
}
timer.start()
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ScrollView
android:layout_width="0dp"
android:layout_height="0dp"
android:fillViewport="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tV_Workout_Name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:editable="false"
android:text="Name of the Workout"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tV_Total_Repetitions" />
<EditText
android:id="@+id/eT_WorkoutName"
android:layout_width="290dp"
android:layout_height="40dp"
android:layout_marginTop="16dp"
android:ems="10"
android:inputType="textPersonName"
android:text="Name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tV_Workout_Name" />
<TextView
android:id="@+id/tV_Prepare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:editable="false"
android:text="Preparation"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/eT_WorkoutName" />
<EditText
android:id="@+id/eT_PrepTime"
android:layout_width="290dp"
android:layout_height="40dp"
android:layout_marginTop="16dp"
android:ems="10"
android:inputType="number"
android:text="0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tV_Prepare" />
<Button
android:id="@+id/btn_Decrement_PrepTime"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_marginTop="56dp"
android:text="-"
app:layout_constraintEnd_toStartOf="@+id/eT_PrepTime"
app:layout_constraintTop_toBottomOf="@+id/eT_WorkoutName" />
<Button
android:id="@+id/btn_Increment_PrepTime"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_marginTop="56dp"
android:text="+"
app:layout_constraintStart_toEndOf="@+id/eT_PrepTime"
app:layout_constraintTop_toBottomOf="@+id/eT_WorkoutName" />
<TextView
android:id="@+id/tV_WorkTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:editable="false"
android:text="Working"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/eT_PrepTime" />
<EditText
android:id="@+id/eT_Work_Time"
android:layout_width="290dp"
android:layout_height="40dp"
android:layout_marginTop="16dp"
android:ems="10"
android:text="0"
android:inputType="number"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tV_WorkTime" />
<Button
android:id="@+id/btn_Decrement_WorkTime"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_marginTop="56dp"
android:text="-"
app:layout_constraintEnd_toStartOf="@+id/eT_Work_Time"
app:layout_constraintTop_toBottomOf="@+id/btn_Decrement_PrepTime" />
<Button
android:id="@+id/btn_Increment_WorkTime"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_marginTop="56dp"
android:text="+"
app:layout_constraintStart_toEndOf="@+id/eT_Work_Time"
app:layout_constraintTop_toBottomOf="@+id/btn_Increment_PrepTime" />
<TextView
android:id="@+id/tv_Repetitions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:editable="false"
android:text="Number of Repetitions"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/eT_Rest_Time" />
<Button
android:id="@+id/btn_Decrement_Repetitions"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_marginTop="56dp"
android:text="-"
app:layout_constraintEnd_toStartOf="@+id/eT_Number_Repetitions"
app:layout_constraintTop_toBottomOf="@+id/btn_Decrement_Rest" />
<Button
android:id="@+id/btn_Increment_Repetitions"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_marginTop="56dp"
android:text="+"
app:layout_constraintStart_toEndOf="@+id/eT_Number_Repetitions"
app:layout_constraintTop_toBottomOf="@+id/btn_Increment_Rest" />
<EditText
android:id="@+id/eT_Number_Repetitions"
android:layout_width="290dp"
android:layout_height="40dp"
android:layout_marginTop="16dp"
android:ems="10"
android:inputType="number"
android:text="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_Repetitions" />
<TextView
android:id="@+id/tV_Rest_Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:editable="false"
android:text="Resting"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/eT_Work_Time" />
<Button
android:id="@+id/btn_Decrement_Rest"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_marginTop="56dp"
android:text="-"
app:layout_constraintEnd_toStartOf="@+id/eT_Rest_Time"
app:layout_constraintTop_toBottomOf="@+id/btn_Decrement_WorkTime" />
<EditText
android:id="@+id/eT_Rest_Time"
android:layout_width="290dp"
android:layout_height="40dp"
android:layout_marginTop="16dp"
android:ems="10"
android:text="0"
android:inputType="number"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tV_Rest_Time" />
<Button
android:id="@+id/btn_Increment_Rest"
android:layout_width="50dp"
android:layout_height="40dp"
android:layout_marginTop="56dp"
android:text="+"
app:layout_constraintStart_toEndOf="@+id/eT_Rest_Time"
app:layout_constraintTop_toBottomOf="@+id/btn_Increment_WorkTime" />
<TextView
android:id="@+id/tV_Total_Duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:editable="false"
android:text="Duration 00:00:00"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tV_Total_Repetitions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:editable="false"
android:text="Repeated for x times"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tV_Total_Duration" />
<Button
android:id="@+id/btn_Start_Timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="52dp"
android:layout_marginEnd="110dp"
android:layout_marginBottom="52dp"
android:text="Start now"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/eT_Number_Repetitions" />
<Button
android:id="@+id/btn_Stop_Timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="110dp"
android:layout_marginTop="52dp"
android:layout_marginBottom="52dp"
android:text="STOP"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/eT_Number_Repetitions" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
我设法导入了图书馆。
但我现在得到以下错误:
只能从coroutine或其他挂起函数调用挂起函数“count down”
未传递参数“handler”的值
代码:
btn_Start_Timer.setOnClickListener() {
val prepTimeMillis = Integer.parseInt(eT_PrepTime.text.toString().trim()) * 1000L;
val workTimeMillis = Integer.parseInt(eT_Work_Time.text.toString().trim()) * 1000L;
val restTimeMillis = Integer.parseInt(eT_Rest_Time.text.toString().trim()) * 1000L;
val numberOfRepetitions = Integer.parseInt(eT_Number_Repetitions.text.toString().trim());
countdownJob = lifecycleScope.launch {
repeat(numberOfRepetitions) {
countDown(prepTimeMillis, 1000L) { millisUntilFinished ->
tV_Total_Duration.setText("Preparation 00:00: " + millisUntilFinished / 1000)
}
countDown(workTimeMillis, 1000L) { millisUntilFinished ->
tV_Total_Duration.setText("Work 00:00: " + millisUntilFinished / 1000)
}
countDown(restTimeMillis, 1000L) { millisUntilFinished ->
tV_Total_Duration.setText("Rest 00:00: " + millisUntilFinished / 1000)
}
}
}
}
btn_Stop_Timer.setOnClickListener(){
}
}
suspend inline fun countDown(millisInFuture: Long, countDownInterval: Long, crossinline onTick: (Long) -> Unit) = withContext(Dispatchers.Main)
{
suspendCancellableCoroutine<Unit>
{ continuation ->
val timer = object: CountDownTimer(millisInFuture, countDownInterval)
{
override fun onTick(millisUntilFinished: Long) = onTick(millisUntilFinished)
override fun onFinish() = continuation.resume(Unit)
}.start()
continuation.invokeOnCancellation()
{
timer.cancel()
}
}
}
编辑:build.gradle(module.app):
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.example.instafollow"
minSdkVersion 24
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation("androidx.lifecycle:lifecycle-viewmodel:2.4.0-rc01")
implementation("androidx.lifecycle:lifecycle-livedata:2.4.0-rc01")
implementation("androidx.lifecycle:lifecycle-runtime:2.4.0-rc01")
implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.4.0-rc01")
annotationProcessor("androidx.lifecycle:lifecycle-compiler:2.4.0-rc01")
implementation("androidx.lifecycle:lifecycle-common-java8:2.4.0-rc01")
implementation("androidx.lifecycle:lifecycle-service:2.4.0-rc01")
implementation("androidx.lifecycle:lifecycle-process:2.4.0-rc01")
implementation("androidx.lifecycle:lifecycle-reactivestreams:2.4.0-rc01")
testImplementation("androidx.arch.core:core-testing:2.1.0")
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.72'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
使用现有类的方法是在第一个类的onfinish()
中嵌套另一个倒计时器,并使用嵌套的倒计时器来倒数工作时间。然后在剩下的时间里,您将在该计时器的onfinish()
中嵌套另一个计时器。但是,因为你想重复整个过程,你必须把它移到一个单独的函数中,这样你就可以重复调用它。所以启动三个计时器的函数也需要一个countdown参数。非常复杂,它看起来像这样:
btn_Start_Timer.setOnClickListener() {
val prepTimeMillis = Integer.parseInt(eT_PrepTime.text.toString().trim()) * 1000L;
val workTimeMillis = Integer.parseInt(eT_PrepTime.text.toString().trim()) * 1000L;
val restTimeMillis = Integer.parseInt(eT_PrepTime.text.toString().trim()) * 1000L;
val numberOfRepetitions = Integer.parseInt(eT_Number_Repetitions.text.toString().trim());
doRep(prepTimeMillis, workTimeMillis, restTimeMillis, numberOfRepetitions)
}
private fun doRep(prepTimeMillis: Long, workTimeMillis: Long, restTimeMillis: Long, times: Int) {
object : CountDownTimer(prepTimeMillis, 1000) {
override fun onTick(millisUntilFinished: Long) {
tV_Total_Duration.setText("Preparation 00:00: " + millisUntilFinished / 1000)
}
override fun onFinish() {
object : CountDownTimer(workTimeMillis, 1000) {
override fun onTick(millisUntilFinished: Long) {
tV_Total_Duration.setText("Work 00:00: " + millisUntilFinished / 1000)
}
override fun onFinish() {
object : CountDownTimer(restTimeMillis, 1000) {
override fun onTick(millisUntilFinished: Long) {
tV_Total_Duration.setText("Rest 00:00: " + millisUntilFinished / 1000)
}
override fun onFinish() {
if (times == 1) {
tV_Total_Duration.setText("All done!")
} else {
doRep(prepTimeMillis, workTimeMillis, restTimeMillis, times - 1)
}
}
}.start()
}
}.start()
}
}.start()
}
这就是所谓的“回调地狱”,在这里您必须深入html" target="_blank">嵌套代码,很难遵循,所以它是使用coroutines进行简化的首选。下面是CountdownTimer的一个挂起函数版本,它允许您按顺序而不是通过嵌套代码来使用它。当您在coroutine中调用这个函数时,您将通常在ontick
函数中执行的操作传递给它。它自动启动计时器,然后coroutine挂起,直到onfinish()
发生,因此可以顺序编写coroutine代码。如果调用它的coroutine被取消,它将取消计时器,因此ontick()
停止被调用。
suspend inline fun countDown(
millisInFuture: Long,
countDownInterval: Long,
crossinline onTick: (Long) -> Unit
) = withContext(Dispatchers.Main) {
suspendCancellableCoroutine<Unit>{ continuation ->
val timer = object: CountDownTimer(millisInFuture, countDownInterval) {
override fun onTick(millisUntilFinished: Long) = onTick(millisUntilFinished)
override fun onFinish() = continuation.resume(Unit)
}.start()
continuation.invokeOnCancellation { timer.cancel() }
}
}
我还将创建一个简单的helper函数来从编辑文本中获取用户输入,并避免代码重复,如下所示:
fun TextView.inputToInt(): Long = text.toString().trim().toIntOrNull() ?: 0
通过这两个函数,您可以使用启动的coroutine在按钮监听器中顺序编写代码:
btn_Start_Timer.setOnClickListener() {
val prepTimeMillis = eT_PrepTime.inputToInt() * 1000L
val workTimeMillis = eT_PrepTime.inputToInt() * 1000L // TODO pick correct ET
val restTimeMillis = eT_PrepTime.inputToInt() * 1000L // TODO pick correct ET
val numberOfRepetitions = eT_Number_Repetitions.inputToInt()
lifecycleScope.launch {
repeat(numberOfRepetitions) {
countDown(prepTimeMillis, 1000L) { millisUntilFinished ->
tV_Total_Duration.setText("Preparation 00:00: " + millisUntilFinished / 1000)
}
countDown(workTimeMillis, 1000L) { millisUntilFinished ->
tV_Total_Duration.setText("Work 00:00: " + millisUntilFinished / 1000)
}
countDown(restTimeMillis, 1000L) { millisUntilFinished ->
tV_Total_Duration.setText("Rest 00:00: " + millisUntilFinished / 1000)
}
}
}
}
请注意,您的设计很容易受到每次屏幕旋转时计时器被重置的影响,因为活动将被破坏并重新创建。我建议将计时器放在ViewModel中,该ViewModel使用可以在活动中观察到的值更新LiveData
,以应用于TextView。但这是一个巨大的话题。您可以阅读有关如何使用ViewModel和LiveData的文档。
编辑:为了支持取消,您需要一个属性来保存coroutine作业。
private var countdownJob: Job? = null
countdownJob?.cancel()
countdownJob = lifecycleScope.launch {
// ... code from above example
}
我的目标操作系统将是Windows7。 如有任何帮助,不胜感激,谢谢。
我有一份Java申请。 应用程序有一个决定应用程序是否在启动时启动的设置。 目前,我通过在StartUp items文件夹中放置/删除快捷方式实现了这一点。 然而,我想知道是否有更好的方法来处理这种行为。 编辑 是的,是视窗。抱歉之前没有清除。 应用程序有一个UI,用户可以在其中触发操作,并且应用程序在运行时定期在后台运行一些任务。 @Peter,如何使用应用程序中的代码更改注册表?这种方法是否与
问题内容: 我已经搜索过SO,但没有找到类似的问题,因为我不确定如何在句子中进行逐步设置。我正在使用带有徽标的ActionBarSherlock,而不是带有活动顶部左上角文本的启动器图标(即72x72图标)。 当活动首次加载时,只需不到一秒的时间。我看到清单中定义的启动器图标和标签(如下所示),然后带徽标的操作栏出现。这个家庭活动非常简单,因此它不会做任何可能导致延迟的额外加载。 我可以通过将其样
我正在尝试使用简单的spring启动应用程序。我在ApplicationContext上启动应用程序时遇到问题。 2017-04-26 11:17:31.101警告14528---[main]s.c.a.AnnotationConfigApplicationContext:上下文初始化期间遇到异常-取消刷新尝试:org。springframework。豆。工厂未满足的PendencyExcepti
我发现Android应用程序非常奇怪的错误,而在Android设备中安装应用程序时具有给定的流程。 > 已从Play商店(旧版)安装该应用程序。 启动应用程序(现在我在主屏幕上,即< code>HomeActivity)。 现在,我通过安装最新版本(正在生产版本,尚未发布到playstore)升级了应用程序。 单击启动器图标,等待主屏幕显示,然后按菜单按钮将应用程序置于后台。 现在,单击启动器图标
目前,我正在收听使用spring boot和spring amqp通过API调用创建的新队列。这是一段成功运行的代码 但如果应用程序再次启动,我需要在容器(DirectMessageListenerContainer)中注册队列,并在应用程序启动时将队列添加到侦听器容器id“queueContainer”中。 我无法侦听队列列表并在启动时将其添加到listner容器。在这方面你能帮忙吗