クイズアプリチュートリアルのキャストエラー【Android Studio, Kotlin】

【Android Studio】Kotlinでつくるクイズアプリ講座 第5回「正解・不正解の判定」|Code for Fun というサイトを見ながら、クイズアプリを作っていた。 しかし、問題発生!!

MainActivity.kt

//省略
val answerBtn: Button = findViewById(view.id)
//省略

というところでエラーが発生してしまいました。

エラーの内容
ClassCastException: com.google.android.material.textview.MaterialTextView cannot be cast to android.widget.Button

つまり、 クラスのキャストについての例外で、 MaterialTextView

android.widget.Button(選択肢のボタン)にキャストできねーぞ!ってことです。

まあ、 超初心者で自分でもよくわかってはいませんが(汗)

とにかく、

val answerBtn: Button = findViewById(view.id)

という書き方がまずい訳です。

対処法

じゃあどうすりゃいいんだよってことでググったら、

val answerBtn = view as MaterialButton

っていう風にやりましょうとありました。

でも結局、同じエラーが出てしまいました。

こういうときのすぐに実行できる最強の手段はchatGPTに聞いちゃうことです。

そこでソースコードと共に投げてみたら、具体的対応が出てきました。 activity_main.xmlの中で IDがanswerBtn1,answerBtn2,answerBtn3,answerBtn4と設定されている<TextViewの部分を<com.google.android.material.button.MaterialButtonに変えろということ。 つまり

activity_main.xml

//省略
<com.google.android.material.button.MaterialButton
    android:id="@+id/answerBtn1"
    android:layout_width="300dp"
    android:layout_height="60dp"
    android:text="@string/btn_answer"
    android:layout_marginTop="6dp"
    style="@style/Widget.MaterialComponents.Button.OutlinedButton"
    android:onClick="checkAnswer" />

<com.google.android.material.button.MaterialButton
    android:id="@+id/answerBtn2"
    android:layout_width="300dp"
    android:layout_height="60dp"
    android:text="@string/btn_answer"
    android:layout_marginTop="6dp"
    style="@style/Widget.MaterialComponents.Button.OutlinedButton"
    android:onClick="checkAnswer" />

<com.google.android.material.button.MaterialButton
    android:id="@+id/answerBtn3"
    android:layout_width="300dp"
    android:layout_height="60dp"
    android:text="@string/btn_answer"
    android:layout_marginTop="6dp"
    style="@style/Widget.MaterialComponents.Button.OutlinedButton"
    android:onClick="checkAnswer" />

<com.google.android.material.button.MaterialButton
    android:id="@+id/answerBtn4"
    android:layout_width="300dp"
    android:layout_height="60dp"
    android:text="@string/btn_answer"
    android:layout_marginTop="6dp"
    style="@style/Widget.MaterialComponents.Button.OutlinedButton"
    android:onClick="checkAnswer" />
//省略

と書き直せということ。

そしたら、解決できました。

学んだこと

当たり前かもしれないけど、キャストができないデータ型の組み合わせがあること。

それは公式ドキュメントかなんかで、今後知ることが必要そうです。

今回のコード

MainActivity.kt

package com.example.quizapp3

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import androidx.appcompat.app.AlertDialog
import com.example.quizapp3.databinding.ActivityMainBinding
import android.content.DialogInterface
import com.google.android.material.button.MaterialButton
import com.google.android.material.button.MaterialButtonToggleGroup

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private var rightAnswer: String? = null
    private var rightAnswerCount = 0
    private var quizCount = 1
    private var QUIZ_COUNT = 5

    private val quizData = mutableListOf(
        mutableListOf("北海道", "札幌市", "長崎市", "福島市", "前橋市"),
        mutableListOf("青森県", "青森市", "広島市", "甲府市", "岡山市"),
        mutableListOf("岩手県", "盛岡市", "大分市", "秋田市", "福岡市"),
        mutableListOf("宮城県", "仙台市", "水戸市", "岐阜市", "福井市"),
        mutableListOf("秋田県", "秋田市", "横浜市", "鳥取市", "仙台市"),
        mutableListOf("山形県", "山形市", "青森市", "山口市", "奈良市"),
        mutableListOf("福島県", "福島市", "盛岡市", "新宿区", "京都市"),
        mutableListOf("茨城県", "水戸市", "金沢市", "名古屋市", "奈良市"),
        mutableListOf("栃木県", "宇都宮市", "札幌市", "岡山市", "奈良市"),
        mutableListOf("群馬県", "前橋市", "福岡市", "松江市", "福井市")
    )

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

        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        quizData.shuffle()//suffle() is function which shuffle the elements

        showNextQuiz()
    }

    fun showNextQuiz(){//Function which display the actually question

        binding.countLabel.text = getString(R.string.count_label, quizCount)//updating count label(%d of Q%d)

        val quiz = quizData[0]//get a question of quiz

        binding.questionLabel.text = quiz[0]//set question

        rightAnswer = quiz[1]//set right answer(Second element of array is right)

        quiz.removeAt(0)//remove 都道府県名(都道府県名 is showed first element of array)

        quiz.shuffle()//shuffle a right answer and three choice

        binding.answerBtn1.text = quiz[0]//Note: First Number of array is "0"
        binding.answerBtn2.text = quiz[1]
        binding.answerBtn3.text = quiz[2]
        binding.answerBtn4.text = quiz[3]

        quizData.removeAt(0)//remove quiz which was showed already
    }

    fun checkAnswer(view: View){
        //what Answer Button is pushed
        val answerBtn =view as MaterialButton
        val btnText = answerBtn.text.toString()

        //make dialog title
        val alertTitle: String
        if(btnText == rightAnswer){
            alertTitle = "正解"
            rightAnswerCount++
        }else{
            alertTitle = "不正解..."
        }

        //make dialog
        AlertDialog.Builder(this).setTitle(alertTitle).setMessage("答え : $rightAnswer").setPositiveButton("OK"){dialogInterface, i -> checkQuizCount()}.setCancelable(false).show()
    }

    fun checkQuizCount(){
        if(quizCount == QUIZ_COUNT){
            //display result screen
        }else{
            quizCount++
            showNextQuiz()
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    tools:context=".MainActivity"
    android:orientation="vertical"
    android:gravity="center"
    tools:ignore="UsingOnClickInXml">

    <TextView
        android:id="@+id/countLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/count_label"
        android:textSize="22sp"/>

    <TextView
        android:id="@+id/questionLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/question_label"
        android:textSize="24sp"
        android:layout_marginTop="60dp"/>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/answerBtn1"
        android:layout_width="300dp"
        android:layout_height="60dp"
        android:text="@string/btn_answer"
        android:layout_marginTop="6dp"
        style="@style/Widget.MaterialComponents.Button.OutlinedButton"
        android:onClick="checkAnswer"
        />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/answerBtn2"
        android:layout_width="300dp"
        android:layout_height="60dp"
        android:text="@string/btn_answer"
        android:layout_marginTop="6dp"
        style="@style/Widget.MaterialComponents.Button.OutlinedButton"
        android:onClick="checkAnswer"
        />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/answerBtn3"
        android:layout_width="300dp"
        android:layout_height="60dp"
        android:text="@string/btn_answer"
        android:layout_marginTop="6dp"
        style="@style/Widget.MaterialComponents.Button.OutlinedButton"
        android:onClick="checkAnswer"
        />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/answerBtn4"
        android:layout_width="300dp"
        android:layout_height="60dp"
        android:text="@string/btn_answer"
        android:layout_marginTop="6dp"
        style="@style/Widget.MaterialComponents.Button.OutlinedButton"
        android:onClick="checkAnswer"
        />

</LinearLayout>

string.xml

<resources>
    <string name="app_name">QuizApp</string>

    <string name="question_label">問題文</string>
    <string name="count_label">Q%d</string>
    <string name="btn_answer">選択肢</string>
</resources>