java.lang.RuntimeException: Unable to instantiate activity
Приложение представляет собой обычный калькулятор. В Android Studio собирается без ошибок, но при запуске на телефоне крашится и выдаёт ошибку:
Код ошибки
2021-05-31 15:43:41.689 19019-19019/mog.isdelal.kotlincalculator E/AndroidRuntime: FATAL EXCEPTION: main
Process: mog.isdelal.kotlincalculator, PID: 19019
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{mog.isdelal.kotlincalculator/mog.isdelal.kotlincalculator.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:2906)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3113)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:113)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:71)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1858)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6820)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)
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:169)
at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:157)
at android.content.Context.obtainStyledAttributes(Context.java:684)
at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:839)
at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:806)
at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:630)
at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:223)
at mog.isdelal.kotlincalculator.MainActivity.<init>(MainActivity.kt:9)
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:69)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
at android.app.Instrumentation.newActivity(Instrumentation.java:1216)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2894)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3113)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:113)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:71)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1858)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6820)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)
2021-05-31 15:43:43.577 19019-19019/mog.isdelal.kotlincalculator I/Process: Sending signal. PID: 19019 SIG: 9
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/taskTextView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="30"
android:gravity="center"
android:hint="0"
android:text=""
android:textSize="30dp" />
<TextView
android:id="@+id/resultTextView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="30"
android:gravity="center"
android:hint="0"
android:text=""
android:textSize="30dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="8">
<Button
android:id="@+id/clearButton"
android:layout_weight="25"
android:layout_height="match_parent"
android:text="C"
android:textSize="30dp"
android:layout_width="0dp"/>
<Button
android:id="@+id/backSpace"
android:layout_weight="25"
android:layout_height="match_parent"
android:text="Back"
android:textSize="18dp"
android:layout_width="0dp"/>
<Button
android:id="@+id/divisionButton"
android:layout_weight="25"
android:layout_height="match_parent"
android:text="/"
android:textSize="30dp"
android:layout_width="0dp"/>
<Button
android:id="@+id/multiplicationButton"
android:layout_weight="25"
android:layout_height="match_parent"
android:text="*"
android:textSize="30dp"
android:layout_width="0dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="12">
<Button
android:id="@+id/button7"
android:layout_weight="25"
android:layout_height="match_parent"
android:text="7"
android:textSize="30dp"
android:layout_width="0dp"/>
<Button
android:id="@+id/button8"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="8"
android:textSize="30dp" />
<Button
android:id="@+id/button9"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="9"
android:textSize="30dp" />
<Button
android:id="@+id/deductionButton"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="-"
android:textSize="30dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="8">
<Button
android:id="@+id/button4"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="4"
android:textSize="30dp" />
<Button
android:id="@+id/button5"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="5"
android:textSize="30dp" />
<Button
android:id="@+id/button6"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="6"
android:textSize="30dp" />
<Button
android:id="@+id/additionButton"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="+"
android:textSize="30dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="8">
<Button
android:id="@+id/button1"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="1"
android:textSize="30dp" />
<Button
android:id="@+id/button2"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="2"
android:textSize="30dp" />
<Button
android:id="@+id/button3"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="3"
android:textSize="30dp" />
<Button
android:id="@+id/dotButton"
android:layout_weight="25"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="."
android:textSize="30dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="8">
<Button
android:id="@+id/openBracket"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="("
android:textSize="30dp" />
<Button
android:id="@+id/button0"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text="0"
android:textSize="30dp" />
<Button
android:id="@+id/closeBacked"
android:layout_weight="25"
android:layout_height="match_parent"
android:layout_width="0dp"
android:text=")"
android:textSize="30dp" />
<Button
android:id="@+id/resultButton"
android:layout_weight="25"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="="
android:textSize="30dp" />
</LinearLayout>
MainActivity.kt
package mog.isdelal.kotlincalculator
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
class MainActivity : AppCompatActivity() {
private val button0: Button = findViewById(R.id.button0)
private val button1: Button = findViewById(R.id.button1)
private val button2: Button = findViewById(R.id.button2)
private val button3: Button = findViewById(R.id.button3)
private val button4: Button = findViewById(R.id.button4)
private val button5: Button = findViewById(R.id.button5)
private val button6: Button = findViewById(R.id.button6)
private val button7: Button = findViewById(R.id.button7)
private val button8: Button = findViewById(R.id.button8)
private val button9: Button = findViewById(R.id.button9)
private val clearButton: Button = findViewById(R.id.clearButton)
private val backSpace: Button = findViewById(R.id.backSpace)
private val divisionButton: Button = findViewById(R.id.divisionButton)
private val multiplicationButton: Button = findViewById(R.id.multiplicationButton)
private val deductionButton: Button = findViewById(R.id.deductionButton)
private val additionButton: Button = findViewById(R.id.additionButton)
private val dotButton: Button = findViewById(R.id.dotButton)
private val resultButton: Button = findViewById(R.id.resultButton)
private val openBracket: Button = findViewById(R.id.openBracket)
private val closeBacked: Button = findViewById(R.id.closeBacked)
private var taskTextView: TextView = findViewById(R.id.taskTextView)
private val resultTextView: TextView = findViewById(R.id.resultTextView)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Ввод строки примера
button0.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "0"
}
button1.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "1"
}
button2.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "2"
}
button3.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "3"
}
button4.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "4"
}
button5.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "5"
}
button6.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "6"
}
button7.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "7"
}
button8.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "8"
}
button9.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "9"
}
clearButton.setOnClickListener {
taskTextView.text = ""
}
backSpace.setOnClickListener {
taskTextView.text = taskTextView.text.toString().dropLast(2)
}
divisionButton.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + " / "
}
multiplicationButton.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + " * "
}
deductionButton.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + " - "
}
additionButton.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + " + "
}
dotButton.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + "."
}
openBracket.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + " ( "
}
closeBacked.setOnClickListener {
taskTextView.text = taskTextView.text.toString() + " ) "
}
//обработка нажатия на =
resultButton.setOnClickListener {
try {
// переводим строку примера в ArrayList<String>, разделяя её по пробелам и удаляя их.
val list: ArrayList<String> = arrayListOf()
val string = taskTextView.text.toString().trim()
var lastIndex = 0
for ((index, value) in string.withIndex()) {
var stringPath = ""
if (value == ' ') {
while (lastIndex < index) {
stringPath += string[lastIndex]
lastIndex++
}
list.add(stringPath)
lastIndex = index + 1
}
}
list.add(string.drop(lastIndex))
resultTextView.text = buildAllFun(list)
} catch (e: Exception) {
taskTextView.text = ""
resultTextView.text = "Ошибка ввода"
}
}
}
// функция buildAllFun проверяет на наличие () в присере и передаёт его дальше в taskInTask, если () есть, или сразу в result, если их нет.
private fun buildAllFun(arr: ArrayList<String>): String {
return if (arr.indexOf("(") != -1) {
taskInTask(arr)[0]
} else {
result(arr)[0]
}
}
// функция taskInTask рекурсивно находит текст простого примера в (), который надо выполнит первым, и исходя из полученного результата, выполняет остальные действия, выходя из рекурсии.
private fun taskInTask(arr: ArrayList<String>): ArrayList<String> {
var indexFirst = 0
var indexLast = 0
for ((index, value) in arr.withIndex()) {
if (value == "(") {
indexFirst = index
}
}
for ((index, value) in arr.withIndex()) {
if (value == ")" && index > indexFirst) {
indexLast = index
break
}
}
indexFirst++
var taskInTaskList: ArrayList<String> = arrayListOf()
while (indexFirst < indexLast) {
taskInTaskList.add(arr[indexFirst])
indexFirst++
}
val result: String = result(taskInTaskList)[0]
taskInTaskList = arr
for ((index, value) in arr.withIndex()) {
if (value == "(") {
indexFirst = index
}
}
taskInTaskList.add(indexFirst++, result)
indexLast++
while (indexLast >= indexFirst) {
taskInTaskList.removeAt(indexLast)
indexLast--
}
return if (taskInTaskList.indexOf("(") != -1) {
taskInTask(taskInTaskList)
} else {
result(taskInTaskList)
}
}
// функция result выполняет счёт простых примеров без () например: "5 + 5 * 5". Возвращает список с одним элементом(ответом).
private fun result(arr: ArrayList<String>): ArrayList<String> {
var a: Double
var b: Double
while (arr.size != 1) {
if (arr.indexOf("/") != -1 || arr.indexOf("*") != -1 || arr.indexOf("-") != -1 || arr.indexOf("+") != -1) {
for ((index, value) in arr.withIndex()) {
if (value == "*") {
a = arr[index - 1].toDouble()
b = arr[index + 1].toDouble()
arr.add(index - 1, (a * b).toString())
arr.removeAt(index + 2)
arr.removeAt(index + 1)
arr.removeAt(index)
break
}
if (value == "/") {
a = arr[index - 1].toDouble()
b = arr[index + 1].toDouble()
arr.add(index - 1, (a / b).toString())
arr.removeAt(index + 2)
arr.removeAt(index + 1)
arr.removeAt(index)
break
}
if (arr.indexOf("/") == -1 && arr.indexOf("*") == -1 && (arr.indexOf("-") != -1 || arr.indexOf("+") != -1)) {
if (value == "+") {
a = arr[index - 1].toDouble()
b = arr[index + 1].toDouble()
arr.add(index - 1, (a + b).toString())
arr.removeAt(index + 2)
arr.removeAt(index + 1)
arr.removeAt(index)
break
}
if (value == "-") {
a = arr[index - 1].toDouble()
b = arr[index + 1].toDouble()
arr.add(index - 1, (a - b).toString())
arr.removeAt(index + 2)
arr.removeAt(index + 1)
arr.removeAt(index)
break
}
}
}
}
}
if (arr[0].toDouble() % 1 == 0.0) {
arr[0] = arr[0].toDouble().toInt().toString()
}
return arr
}
}
P.S. Я новичок, поэтому мне было бы полезно послушать обоснованную критику в адрес моего кода, чтобы в будущем писать его более чистым. Заранее спасибо
Ответы (1 шт):
Автор решения: Alex Sus
→ Ссылка
Вот здесь:
class MainActivity : AppCompatActivity() {
private val button0: Button = findViewById(R.id.button0)
private val button1: Button = findViewById(R.id.button1)
...
идет обращение к элементам, которые еще не созданы в текущий момент, естественно получается ошибка. А созданы они будут только после того, как в onCreate сработает строка setContentView(R.layout.activity_main), т.е. вам нужно все эти ваши privat val ... перенести и поставить после этой строки. Чтобы работать с Андроидом нужно хорошо понимать, что в какой момент создается.
И насчет "писать код более чистым": в 2021 году пользоваться findViewById уже не комильфо. Почитайте про View Binding