这个错误的原因可能是什么? (Kotlin) (AndroidRuntime: FATAL EXCEPTION: main)

What could be the cause of this error? (Kotlin) (AndroidRuntime: FATAL EXCEPTION: main)

调试我的应用程序时出现以下错误:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.studycountdowntimer, PID: 16161
    java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.studycountdowntimer/com.example.studycountdowntimer.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3395)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3651)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2104)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:236)
        at android.app.ActivityThread.main(ActivityThread.java:7861)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:600)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
        at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:184)
        at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:174)
        at android.content.Context.obtainStyledAttributes(Context.java:753)
        at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:842)
        at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:809)
        at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:633)
        at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:259)
        at com.example.studycountdowntimer.MainActivity.<init>(MainActivity.kt:19)
        at java.lang.Class.newInstance(Native Method)
        at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
        at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
        at android.app.Instrumentation.newActivity(Instrumentation.java:1254)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3383)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3651) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2104) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:236) 
        at android.app.ActivityThread.main(ActivityThread.java:7861) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:600) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967) 
I/Process: Sending signal. PID: 16161 SIG: 9
Disconnected from the target VM, address: 'localhost:58274', transport: 'socket'

这是 activity_main.xml 代码:

<?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"
    android:background="#673AB7"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/inputTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@null"
        android:hint="@string/inputTime"
        android:importantForAutofill="no"
        android:inputType="number"
        android:minWidth="48dp"
        android:minHeight="48dp"
        android:textAlignment="center"
        android:textColor="#FFFFFF"
        android:textColorHighlight="#AE81FF"
        android:textColorHint="#7AFFFFFF"
        android:textColorLink="@null"
        android:textCursorDrawable="@android:drawable/btn_default"
        android:textSize="44sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.35"
        tools:ignore="TextContrastCheck,DuplicateSpeakableTextCheck" />

    <TextView
        android:id="@+id/showTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minWidth="48dp"
        android:minHeight="48dp"
        android:textAlignment="center"
        android:textColor="#FFFFFF"
        android:textColorHighlight="#AE81FF"
        android:textSize="44sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.35"
        tools:text="00:00:00" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/startButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="96dp"
        android:layout_marginTop="44dp"
        android:clickable="true"
        android:contentDescription="@string/startButton"
        android:focusable="true"
        android:tint="#FFFFFF"
        app:backgroundTint="#EE7745CF"
        app:fabCustomSize="80dp"
        app:fabSize="auto"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/inputTime"
        app:maxImageSize="35dp"
        app:srcCompat="@android:drawable/ic_media_play"
        tools:ignore="SpeakableTextPresentCheck,ImageContrastCheck,DuplicateClickableBoundsCheck" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/pauseButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="96dp"
        android:layout_marginTop="44dp"
        android:clickable="true"
        android:contentDescription="@string/pauseButton"
        android:focusable="true"
        android:tint="#FFFFFF"
        android:visibility="invisible"
        app:backgroundTint="#EE7745CF"
        app:fabCustomSize="80dp"
        app:fabSize="auto"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/inputTime"
        app:maxImageSize="35dp"
        app:srcCompat="@android:drawable/ic_media_pause"
        tools:ignore="ImageContrastCheck" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/stopButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="45dp"
        android:layout_marginEnd="96dp"
        android:clickable="true"
        android:contentDescription="@string/stopButton"
        android:focusable="true"
        android:tint="#FFFFFF"
        app:backgroundTint="#EE7745CF"
        app:fabCustomSize="80dp"
        app:fabSize="auto"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/inputTime"
        app:maxImageSize="35dp"
        app:srcCompat="@drawable/ic_media_stop"
        tools:ignore="SpeakableTextPresentCheck" />

</androidx.constraintlayout.widget.ConstraintLayout>

和 MainActivity.kt:

package com.example.studycountdowntimer

import android.annotation.SuppressLint
import android.os.Bundle
import android.os.CountDownTimer
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private var startMilliseconds = 60000L

    private lateinit var cdTimer: CountDownTimer
    private var onRun: Boolean = false
    var timeInMilliseconds = 0L

    private val timeInput: EditText = findViewById(R.id.inputTime)
    private val timeShow: TextView = findViewById(R.id.showTime)
    private val buttonStart: Button = findViewById(R.id.startButton)
    private val buttonPause: Button = findViewById(R.id.pauseButton)
    private val buttonStop: Button = findViewById(R.id.stopButton)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        buttonStart.setOnClickListener {
            if (onRun) {
                pauseTime()
                buttonPause.visibility = View.VISIBLE

            } else {
                val time  = timeInput.text.toString()
                timeInMilliseconds = time.toLong() *60000L
                startTime(timeInMilliseconds)
            }
        }

        buttonStop.setOnClickListener {
            stopTime()
        }

    }

    private fun pauseTime() {

        cdTimer.cancel()
        onRun = false

    }

    private fun startTime(timeInSeconds: Long) {
        cdTimer = object : CountDownTimer(timeInSeconds, 1000) {
            @SuppressLint("SetTextI18n")
            override fun onFinish() {
                timeShow.text = "You did it!"
            }

            override fun onTick(p0: Long) {
                timeInMilliseconds = p0
                updateTextUI()
            }
        }
        cdTimer.start()

        onRun = true
        buttonStart.visibility = View.INVISIBLE

    }

    private fun stopTime() {
        timeInMilliseconds = startMilliseconds
        updateTextUI()
    }

    @SuppressLint("SetTextI18n")
    private fun updateTextUI() {
        val minutes = (timeInMilliseconds / 1000) / 60
        val seconds = (timeInMilliseconds / 1000) % 60
        val hours = minutes / 60

        timeShow.text = "$hours:$minutes:$seconds"
    }
}

可能发生了什么? 提前致谢!

我复制了代码,很快就调试好了。我找到了原因并修复了崩溃。

重现崩溃

原因

正如 Alex 所说 findViewById 的方法在 onCreate()

之前被调用

解决方案

使用 lateinit var 延迟启动这些属性。

    private lateinit var timeInput: EditText
    private lateinit var timeShow: TextView
    private lateinit var buttonStart: FloatingActionButton
    private lateinit var buttonPause: FloatingActionButton
    private lateinit var buttonStop: FloatingActionButton


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        timeInput = findViewById(R.id.inputTime)
        timeShow = findViewById(R.id.showTime)
        buttonStart = findViewById(R.id.startButton)
        buttonPause = findViewById(R.id.pauseButton)
        buttonStop = findViewById(R.id.stopButton)
...
}

注意:还有其他崩溃,例如,private lateinit var buttonStart: Button会导致此崩溃:

我们需要从崩溃日志中了解这次崩溃的含义,所以我将 Button 更改为 FloatingActionButton

享受编程的乐趣。