クイズアプリチュートリアルのキャストエラー【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>