I'm working on a project that updates a textview with text when a button is pressed. For example, you press 0 and 0 displays on the textview. When the device changes orientation, such as when the user rotates their device, the application crashes.
When I comment out the button0.setOnClickListener(new Buttons(request, "0"));
line the application does not crash.
I have verified that there is a Button with the id "zero" in both the portrait and landscape layouts.
The layouts are stored in:
res/layout/activity_main.xml
res/layout-land/activity_main.xml
There are no warnings or error messages in either layout and (again) both layouts function when the ".setOnclickListener()" line of code is not included in the "MainActivity".
First Class. MainActivity.java:
package com.example.myapp;
import android.content.res.Configuration;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
public class MainActivity extends AppCompatActivity {
Button button0;
TextView request;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
request = findViewById(R.id.request);
// Number Buttons
button0 = findViewById(R.id.zero);
button0.setOnClickListener(new Buttons(request, "0"));
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
}
}
Second Class. Buttons.java:
package com.example.myapp;
import android.view.View;
import android.widget.TextView;
import static androidx.core.content.res.TypedArrayUtils.getText;
public class Buttons implements View.OnClickListener {
TextView tv;
String text;
public Buttons(TextView tv, String input){
this.tv = tv;
this.text = input;
}
public Buttons(TextView tv){
this.tv = tv;
this.text = "";
}
@Override
public void onClick(View view) {
if (tv.getText().toString().equals("Request")){
tv.setText(text);
}
else {
String response = tv.getText().toString() + text;
tv.setText(response);
}
}
}
I've tried attaching this to the MainActivity.java class:
@Override
protected void onDestroy() {
button0.setOnClickListener(null);
super.onDestroy();}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
Here is the Logcat:
FATAL EXCEPTION: main
Process: com.example.texascal, PID: 9311
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.texascal/com.example.texascal.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4164)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4322)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:6499)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:6378)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:76)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8919)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.example.texascal.MainActivity.onCreate(MainActivity.java:82)
at android.app.Activity.performCreate(Activity.java:8975)
at android.app.Activity.performCreate(Activity.java:8944)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4146)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4322)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:6499)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:6378)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:76)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8919)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
2024-07-23 15:21:58.653 9311-9311 Process com.example.texascal I Sending signal. PID: 9311 SIG: 9
---------------------------- PROCESS ENDED (9311) for package com.example.texascal ----------------------------
I identified the problem. After learning how to use logcat, it was revealed that I had duplicate layouts for various device size to adapt or respond to different android device form-factors. While a Button with the id zero existed in several of the different layouts it did not exist for all of the layouts. The solution was to verify the 0 button had an id for every layout.
<Button
...
android:text="0"
android:id="@+id/zero"/>