You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
}

额外优化建议

  1. 处理空输入或非数字输入:当前代码直接调用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()
            }
        }
    }
    
  2. 使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 07:08:10