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) // 后续其他代码 }
额外优化点
- 给
mQuestionsList添加非空判断,避免!!强制解包触发空指针:
mQuestionsList = Consts.getQuestions() if (mQuestionsList.isNullOrEmpty()) { Toast.makeText(this, "暂无题目数据", Toast.LENGTH_SHORT).show() finish() return }
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
相关产品推荐
相关产品推荐

