Kotlin平均速度计算Android程序崩溃问题求助
问题排查:Kotlin Android平均速度计算程序点击崩溃
开发Kotlin Android平均速度计算程序时,点击计算按钮触发崩溃,报错:
kotlin.UninitializedPropertyAccessException: lateinit property etT0 has not been initialized
完整错误日志
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.activityspeed, PID: 10600 kotlin.UninitializedPropertyAccessException: lateinit property etT0 has not been initialized at com.example.activityspeed.MainActivity.getEtT0(MainActivity.kt:18) at com.example.activityspeed.MainActivity.onClick(MainActivity.kt:44) at android.view.View.performClick(View.java:7125) at android.view.View.performClickInternal(View.java:7102) at android.view.View.access$3500(View.java:801) at android.view.View$PerformClick.run(View.java:27336) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) I/Process: Sending signal. PID: 10600 SIG: 9 Disconnected from the target VM, address: 'localhost:58784', transport: 'socket'
Kotlin代码
package com.example.atividadevelocidade import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.widget.AppCompatButton import androidx.appcompat.widget.AppCompatEditText import kotlin.math.pow class MainActivity : AppCompatActivity(), View.OnClickListener { lateinit var btCalcularVelo: AppCompatButton lateinit var etV1: AppCompatEditText lateinit var etV0: AppCompatEditText lateinit var etT1: AppCompatEditText lateinit var etT0: AppCompatEditText override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) etV1 = findViewById(R.id.etV1) etV0 = findViewById(R.id.etV0) btCalcularVelo = findViewById(R.id.btCalcularVelo) btCalcularVelo.setOnClickListener(this) } private fun calcularVelo(v1: Double, v0: Double, t1: Double, t0: Double) : Double{ if (v1 > 0.0 && v0 >= 0.0 && t1 > 0.0 && t0 >= 0.0) { return (((v1 - v0) / (t1 - t0))) } else { throw IllegalArgumentException("Ta Errado.") } } override fun onClick(v: View?) { if(v!!.id == R.id.btCalcularVelo) { val v0 = etV0.text.toString().toDouble() val v1 = etV1.text.toString().toDouble() val t0 = etT0.text.toString().toDouble() val t1 = etT1.text.toString().toDouble() val resultado = calcularVelo(v1, v0, t1, t0) Toast.makeText(this, "A velocidade media é: $resultado", Toast.LENGTH_LONG) .show() } } }
XML布局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" android:gravity="center" tools:context=".MainActivity"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/tvTitulo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Caluclador de Velocidade media" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/tvV0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tvTitulo" android:text="Velocidade Inicial:" android:layout_marginTop="15dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatEditText android:id="@+id/etV0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tvV0" android:scaleX="2" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/tvV1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/etV0" android:text="Velocidade Final:" android:layout_marginTop="25dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatEditText android:id="@+id/etV1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tvV1" android:scaleX="2" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/tvT1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/etV1" android:text="Tempo Final:" android:layout_marginTop="25dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatEditText android:id="@+id/etT1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tvT1" android:scaleX="2" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/tvT0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/etT1" android:text="Tempo Inicial:" android:layout_marginTop="15dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatEditText android:id="@+id/etT0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tvT0" android:scaleX="2" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" /> <androidx.appcompat.widget.AppCompatButton android:id="@+id/btCalcularVelo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/etT0" android:text="Calcular" android:layout_marginTop="15dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </RelativeLayout>
原因分析
代码中声明了etT1和etT0两个lateinit变量,但在onCreate方法里只初始化了etV1、etV0和btCalcularVelo,没有调用findViewById给etT1和etT0赋值。点击按钮触发onClick方法时,尝试访问这两个未初始化的变量,就会抛出UninitializedPropertyAccessException异常,导致程序崩溃。
修复方案
在onCreate方法中添加etT1和etT0的初始化代码,修改后的onCreate如下:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) etV1 = findViewById(R.id.etV1) etV0 = findViewById(R.id.etV0) // 添加以下两行初始化代码 etT1 = findViewById(R.id.etT1) etT0 = findViewById(R.id.etT0) btCalcularVelo = findViewById(R.id.btCalcularVelo) btCalcularVelo.setOnClickListener(this) }
额外优化建议
处理空输入或非数字输入:当前代码直接调用
toDouble(),如果用户输入为空或非数字,会抛出NumberFormatException。可以添加输入校验:override fun onClick(v: View?) { if(v!!.id == R.id.btCalcularVelo) { val v0Str = etV0.text.toString().trim() val v1Str = etV1.text.toString().trim() val t0Str = etT0.text.toString().trim() val t1Str = etT1.text.toString().trim() // 校验输入是否为空 if (listOf(v0Str, v1Str, t0Str, t1Str).any { it.isEmpty() }) { Toast.makeText(this, "请填写所有字段", Toast.LENGTH_LONG).show() return } // 校验输入是否为有效数字 val v0 = try { v0Str.toDouble() } catch (e: NumberFormatException) { Toast.makeText(this, "Velocidade Inicial格式错误", Toast.LENGTH_LONG).show() return } val v1 = try { v1Str.toDouble() } catch (e: NumberFormatException) { Toast.makeText(this, "Velocidade Final格式错误", Toast.LENGTH_LONG).show() return } val t0 = try { t0Str.toDouble() } catch (e: NumberFormatException) { Toast.makeText(this, "Tempo Inicial格式错误", Toast.LENGTH_LONG).show() return } val t1 = try { t1Str.toDouble() } catch (e: NumberFormatException) { Toast.makeText(this, "Tempo Final格式错误", Toast.LENGTH_LONG).show() return } try { val resultado = calcularVelo(v1, v0, t1, t0) Toast.makeText(this, "A velocidade media é: $resultado", Toast.LENGTH_LONG).show() } catch (e: IllegalArgumentException) { Toast.makeText(this, e.message, Toast.LENGTH_LONG).show() } } }使用ViewBinding替代findViewById:ViewBinding可以避免手动初始化View时的遗漏,更安全且代码更简洁。在模块的
build.gradle中开启ViewBinding:android { ... buildFeatures { viewBinding true } }然后修改
MainActivity代码:class MainActivity : AppCompatActivity(), View.OnClickListener { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.btCalcularVelo.setOnClickListener(this) } private fun calcularVelo(v1: Double, v0: Double, t1: Double, t0: Double) : Double{ if (v1 > 0.0 && v0 >= 0.0 && t1 > 0.0 && t0 >= 0.0) { return (((v1 - v0) / (t1 - t0))) } else { throw IllegalArgumentException("Ta Errado.") } } override fun onClick(v: View?) { if(v!!.id == R.id.btCalcularVelo) { // 通过binding直接访问View,无需手动初始化 val v0 = binding.etV0.text.toString().toDouble() val v1 = binding.etV1.text.toString().toDouble() val t0 = binding.etT0.text.toString().toDouble() val t1 = binding.etT1.text.toString().toDouble() try { val resultado = calcularVelo(v1, v0, t1, t0) Toast.makeText(this, "A velocidade media é: $resultado", Toast.LENGTH_LONG).show() } catch (e: IllegalArgumentException) { Toast.makeText(this, e.message, Toast.LENGTH_LONG).show() } } } }
内容的提问来源于stack exchange,提问作者CanarinDoHexa
相关产品推荐
相关产品推荐

