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

Kotlin代码触发NullPointerException:测验页面跳转后应用崩溃求助

问题分析与解决方案

崩溃根源

你代码里的image1是在类成员变量声明阶段直接调用findViewById初始化的:

private var image1:ImageView= findViewById(R.id.iv_image)

此时Activity还未执行setContentView加载布局,也未完成上下文初始化,调用findViewById不仅会返回null,还会因Context为空触发NullPointerException。而其他控件用了延迟初始化的getter形式(private val xxx:View get()= findViewById(...)),只会在实际调用时才执行查找,所以没有问题。

修复方案

方案1:将image1改为延迟getter初始化

和其他控件保持一致,把image1的声明修改为:

private val image1:ImageView get()= findViewById(R.id.iv_image)

方案2:用lateinit延迟初始化

先声明变量,在onCreate里完成初始化:

private lateinit var image1:ImageView

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_quiz_questions)
    image1 = findViewById(R.id.iv_image)
    // 后续其他代码
}

额外优化点

  1. 给mQuestionsList添加非空判断,避免!!强制解包触发空指针:
mQuestionsList = Consts.getQuestions()
if (mQuestionsList.isNullOrEmpty()) {
    Toast.makeText(this, "暂无题目数据", Toast.LENGTH_SHORT).show()
    finish()
    return
}
  1. onClick里直接用资源ID常量判断,比调用控件id更稳妥:
override fun onClick(p0: View?) {
    p0?.let { view ->
        when (view.id){
            R.id.tv_option_one -> selectedOptionView(textView1, 1)
            R.id.tv_option_two -> selectedOptionView(textView2, 2)
            R.id.tv_option_three -> selectedOptionView(textView3, 3)
            R.id.tv_option_four -> selectedOptionView(textView4, 4)
        }
    }
}

完整修复后代码示例

package com.example.quizviolence

import android.annotation.SuppressLint
import android.graphics.Typeface
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat

class QuizQuestions : AppCompatActivity(), View.OnClickListener {
    private var mCurrentPos: Int = 1
    private var mQuestionsList: ArrayList<Question>?= null
    private var mSelectedOptionPos: Int = 0

    private val progress1:TextView get()= findViewById(R.id.tv_progress)
    private val progressBar1:ProgressBar get() = findViewById(R.id.progressBar)
    private val question1:TextView get()= findViewById(R.id.tv_question)
    private val textView1:TextView get()= findViewById(R.id.tv_option_one)
    private val textView2:TextView get()= findViewById(R.id.tv_option_two)
    private val textView3:TextView get()= findViewById(R.id.tv_option_three)
    private val textView4:TextView get()= findViewById(R.id.tv_option_four)
    private val image1:ImageView get()= findViewById(R.id.iv_image)

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

        mQuestionsList = Consts.getQuestions()
        if (mQuestionsList.isNullOrEmpty()) {
            Toast.makeText(this, "暂无题目数据", Toast.LENGTH_SHORT).show()
            finish()
            return
        }
        setQuestion()
        textView1.setOnClickListener(this)
        textView2.setOnClickListener(this)
        textView3.setOnClickListener(this)
        textView4.setOnClickListener(this)
    }

    @SuppressLint("SetTextI18n")
    private fun setQuestion() {
        mCurrentPos=1
        val questionListNew= mQuestionsList!![mCurrentPos-1]
        defaultOptionView()
        progressBar1.progress = mCurrentPos
        progress1.text = "$mCurrentPos/${progressBar1.max}"
        question1.text = questionListNew.question
        image1.setImageResource(questionListNew.image)
        textView1.text = questionListNew.optionOne
        textView2.text = questionListNew.optionTwo
        textView3.text = questionListNew.optionThree
        textView4.text = questionListNew.optionFour
        mCurrentPos += 1
    }
    private fun defaultOptionView(){
        val options=ArrayList<TextView>()
        options.add(textView1)
        options.add(textView2)
        options.add(textView3)
        options.add(textView4)

        for (option in options){
            option.setTextColor(0xFF7A8089.toInt())
            option.typeface= Typeface.DEFAULT
            option.background=ContextCompat.getDrawable(this,R.drawable.default_option_boarder_bg)
        }
    }

    override fun onClick(p0: View?) {
          p0?.let { view ->
              when (view.id){
                  R.id.tv_option_one -> selectedOptionView(textView1, 1)
                  R.id.tv_option_two -> selectedOptionView(textView2, 2)
                  R.id.tv_option_three -> selectedOptionView(textView3, 3)
                  R.id.tv_option_four -> selectedOptionView(textView4, 4)
              }
          }
    }
    private fun selectedOptionView(tv: TextView,selectedOptionNumber:Int)  {
        defaultOptionView()
        mSelectedOptionPos= selectedOptionNumber
        tv.setTextColor(0xFF363A43.toInt())
        tv.setTypeface(tv.typeface,Typeface.BOLD)
        tv.background=ContextCompat.getDrawable(this,R.drawable.selected_option_boarder_bg)
    }
}

内容的提问来源于stack exchange,提问作者Fidias

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 19:00:37