1

hello everyone i'm new here and new to android development, first i want to apologize if this was asked and answered before. i'm trying to build an android app and in the user profile i have 2 radio buttons for gender, male and female. i was able to pass the value of the selected radio button to the firebase database. this is the code i used:

    saveUserProfile.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String dogBirthdate = displayDogBirthday.getText().toString();
            String dogGender = radioBtnDogGender.getText().toString();
            String dogNeutered = radioBtnNeutered.getText().toString();
            String aboutTheDog = aboutDog.getText().toString();

            progressBar.setVisibility(View.VISIBLE);

            //userId = fireAuth.getCurrentUser().getUid();
            documentReference = fireStore.collection("users").document(userId);
            Map<String, Object> user = new HashMap<>();
            user.put("dogBirthdate", dogBirthdate);
            user.put("dogGender", dogGender);
            user.put("dogNeutered", dogNeutered);
            user.put("aboutDog", aboutTheDog);

and this for the radio button selection

public void radioBtnGenderClick(View view) {
    int radioBtnDogGenderId = radioGroupDogGender.getCheckedRadioButtonId();
    radioBtnDogGender = (RadioButton) findViewById(radioBtnDogGenderId);

    Toast.makeText(getBaseContext(),radioBtnDogGender.getText(),Toast.LENGTH_LONG).show();
}

i was able to pass back the value of the gender as text to the user profile screen

userId = fireAuth.getCurrentUser().getUid();

    documentReference = fireStore.collection("users").document(userId);
    documentReference.addSnapshotListener(new EventListener<DocumentSnapshot>() {
        @Override
        public void onEvent(@Nullable DocumentSnapshot value, @Nullable FirebaseFirestoreException error) {
            dogName.setText(value.getString("dogName"));
            aboutDog.setText(value.getString("aboutDog"));
            displayDogBirthday.setText(value.getString("dogBirthdate"));

            String gender = value.getString("dogGender");
            if (gender.equalsIgnoreCase("Male")){
                radioBtnMale.setChecked(true);


            }else if (gender.equalsIgnoreCase("Female")){
                radioBtnFemale.setChecked(true);
            }

when i go to the Edit User Profile the correct radio button is showen as checked, however when i click on Save Profile the app crashes like it did when no radio button was checked. if i reclick the same radio button in the edit profile page everything works ok.

how can i fix it so that the user won't have to reclick the radio button (unless he wants to change the selection) and that when saving the profile it will recognize the button as checked?

i think the issue is that when passing the radio button value to the database "radioBtnDogGender" is used and when passing back the value from the database the "radioBtmMale"/"radioBtnFemale" are used.

how can i pass the value into the "radioBtnDogGender" instead of the specific Male/Female radio buttons?

this is the xml code:

<RadioGroup
    android:id="@+id/radioGroupDogGender"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.488"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.459">

    <RadioButton
        android:id="@+id/radioBtnMale"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="radioBtnGenderClick"
        android:text="Male" />

    <RadioButton
        android:id="@+id/radioBtnFemale"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="radioBtnGenderClick"
        android:text="Female" />

</RadioGroup>

here is the stack trace when app crashes (pressing on save profile without reclicking the radio button):

2021-03-11 14:54:59.303 13459-13459/com.example.loginandregfirebase E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.loginandregfirebase, PID: 13459
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.CharSequence android.widget.RadioButton.getText()' on a null object reference
    at com.example.loginandregfirebase.EditUserProfilePage$7.onClick(EditUserProfilePage.java:205)
    at android.view.View.performClick(View.java:7448)
    at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
    at android.view.View.performClickInternal(View.java:7425)
    at android.view.View.access$3600(View.java:810)
    at android.view.View$PerformClick.run(View.java:28305)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

as i mentioned in the comments the Gender radio buttons works fine with the new code and when i tried to implement the same code to the Neutered radio buttons i got a new problem, the Neutered radio buttons stay empty and when i physically press on one of them the app restarts while leaving the Neutered radio buttons empty, in the View profile under Neutered it says "unspecified" here is the code for both the Gender and Neutered radio buttons

            radioGroupDogGender.clearCheck();
            radioGroupNeutered.clearCheck();
            String gender = value.getString("dogGender");

            if (gender == null || gender.equalsIgnoreCase("Unspecified gender")){
                // gender unknown, leave unselected
                radioGroupDogGender = null;
            }else

            if (gender.equalsIgnoreCase("Male")){
                radioBtnMale.setChecked(true);
                radioBtnDogGender = radioBtnMale;


            }else if (gender.equalsIgnoreCase("Female")){
                radioBtnFemale.setChecked(true);
                radioBtnDogGender = radioBtnFemale;
            }

            String neutered = value.getString("dogNeutered");

            if (neutered == null || neutered.equalsIgnoreCase("Unspecified")){
                // neutered unknown, leave unselected
                radioGroupNeutered = null;
            }else

            if (neutered.equalsIgnoreCase("Yes")){
                radioBtnNeuteredYes.setChecked(true);
                radioBtnNeutered = radioBtnNeuteredYes;
            }else if (neutered.equalsIgnoreCase("No")){
                radioBtnNeuteredNo.setChecked(true);
                radioBtnNeutered = radioBtnNeuteredNo;
            }




saveUserProfile.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String dogBirthdate = displayDogBirthday.getText().toString();
            String dogGender = radioBtnDogGender != null ? radioBtnDogGender.getText().toString():"unspecified gender";
            //String dogGender = radioBtnDogGender.getText().toString();
            String dogNeutered = radioBtnNeutered != null ? radioBtnNeutered.getText().toString(): "unspecified";
            //String dogNeutered = radioBtnNeutered.getText().toString();
            String aboutTheDog = aboutDog.getText().toString();

            progressBar.setVisibility(View.VISIBLE);

            //userId = fireAuth.getCurrentUser().getUid();
            documentReference = fireStore.collection("users").document(userId);
            Map<String, Object> user = new HashMap<>();
            user.put("dogBirthdate", dogBirthdate);
            user.put("dogGender", dogGender);
            user.put("dogNeutered", dogNeutered);
            user.put("aboutDog", aboutTheDog);


public void radioBtnGenderClick(View view) {
    int radioBtnDogGenderId = radioGroupDogGender.getCheckedRadioButtonId();
    if (radioBtnDogGenderId == -1){
        //gender deselected
        Toast.makeText(getBaseContext(),"gender deselected", Toast.LENGTH_LONG).show();
    }else {
        radioBtnDogGender = (RadioButton) findViewById(radioBtnDogGenderId);

        Toast.makeText(getBaseContext(), radioBtnDogGender.getText(), Toast.LENGTH_LONG).show();
    }
}

public void radioBtnNeutered(View view) {
    int radioBtnNeuteredId = radioGroupNeutered.getCheckedRadioButtonId();
    if (radioBtnNeuteredId == -1){
        Toast.makeText(getBaseContext(),"neutered deselected",Toast.LENGTH_LONG).show();
    }else {
        radioBtnNeutered = (RadioButton) findViewById(radioBtnNeuteredId);

        Toast.makeText(getBaseContext(), radioBtnNeutered.getText(), Toast.LENGTH_LONG).show();
    }
}

did i forget anything or is a different code needed for the Neutered radio buttons?

1
  • If the app crashes, there is a stack trace. Please look that up on logcat, and add it to your question. Commented Mar 11, 2021 at 13:36

1 Answer 1

2

To start with, in your onEvent handler, you disregard the value of error, which may lead to your crash as you try to access a potentially null value for value. The first line of your onEvent handler should check if the listener has failed.

public void onEvent(@Nullable DocumentSnapshot value, @Nullable FirebaseFirestoreException error) {
    if (error != null) {
        // something has gone wrong, handle it
        return;
    }

    // no errors, continue
    // ...
}

The error could also come from the below lines:

String gender = value.getString("dogGender");
if (gender.equalsIgnoreCase("Male")){
    radioBtnMale.setChecked(true);
} else if (gender.equalsIgnoreCase("Female")) {
    radioBtnFemale.setChecked(true);
}

When your user loads up their profile for the first time, the value for dogGender may be null. When it is null, you try to call null.equalsIgnoreCase(...) which will throw a NullPointerException. Instead, you should check if it's null before comparing it to Female and Male. In addition, when changing the currently selected radio button programmatically, it won't call the radioBtnGenderClick listener which means that radioBtnDogGender doesn't get updated - so we update that here.

radioGroupDogGender.clearCheck();
String gender = value.getString("dogGender");
if (gender == null || gender.equalsIgnoreCase("Unspecified")) {
    // gender unknown, leave unselected
    radioBtnDogGender = null;
} else if (gender.equalsIgnoreCase("Male")) {
    radioBtnMale.setChecked(true);
    radioBtnDogGender = radioBtnMale;
} else if (gender.equalsIgnoreCase("Female")) {
    radioBtnFemale.setChecked(true);
    radioBtnDogGender = radioBtnFemale;
}

While I've been typing this out, now that you've provided the stack trace for your error, we can actually see that the lines causing the error are:

public void radioBtnGenderClick(View view) {
    int radioBtnDogGenderId = radioGroupDogGender.getCheckedRadioButtonId();
    radioBtnDogGender = (RadioButton) findViewById(radioBtnDogGenderId);

    Toast.makeText(getBaseContext(),radioBtnDogGender.getText(),Toast.LENGTH_LONG).show();
}

and

saveUserProfile.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // ...
        String dogGender = radioBtnDogGender.getText().toString();
        // ...
    }
}

As mentioned above, the radioBtnGenderClick listener isn't called when you update the selected radio button using setChecked() so radioGroupDogGender could be null until the user clicks one of the gender options unless you apply the changes above where you manually set radioBtnDogGender. When the radioBtnGenderClick listener is executed while there are no actively selected radio buttons in radioGroupDogGender, radioGroupDogGender.getCheckedRadioButtonId() returns a value of -1. On the next line, you call findViewById(-1) which then sets the value of radioBtnDogGender to null. Following that you effectively call ((RadioButton) null).getText() which throws a NullPointerException.

public void radioBtnGenderClick(View view) {
    int radioBtnDogGenderId = radioGroupDogGender.getCheckedRadioButtonId();
    if (radioBtnDogGenderId == -1) {
        // gender deselected
        Toast.makeText(getBaseContext(),"Gender deselected",Toast.LENGTH_LONG).show();
    } else {
        radioBtnDogGender = (RadioButton) findViewById(radioBtnDogGenderId);
        Toast.makeText(getBaseContext(),radioBtnDogGender.getText(),Toast.LENGTH_LONG).show();
    }
}

Similarly, you also assume that radioBtnDogGender is not null in the onClickListener of your saveUserProfile button.

String dogGender = radioBtnDogGender != null ? radioBtnDogGender.getText().toString() : "Unspecified";
Sign up to request clarification or add additional context in comments.

8 Comments

As an addendum, I would also reconsider your database structure so that you can accommodate users who have multiple dogs. /users/{uid} would be the owners, and /dogs/{dogId} (or /users/{uid}/dogs/{dogId}) would be the info about the dogs (with a owner = "someUID" property)
first thank you for your answer. when calling the value back from the database the correct radio button (radioBtnMale/radioBtnFemale) shows as checked. as you mentioned the radioBtnDogGender is not activly selected, how can i fix it that the radioBtnDogGender will automatically be selected with the relevant selection returened from the database? about your sugestion for multiple dogs per user, for the time being i want to concentrate on one dog per user, in the future i might add the option for multiple dogs
Just before String gender = ..., try adding radioGroupDogGender.clearCheck();
i tried the clearCheck, unfortunately i get the same result, visualy the radio button is checked but it dosen't fill the radioBtnDogGender value and it stays empty, is there a way to pass the value of the radioBtnMale/Female into the radioBtnDogGender?
thank for that, the dog gender works fine, it gets the value from the database and doesn't crash when i save the profile without physically pressing/repressing the gender radio button. i tried to implement the same code to the neutered radio button but for some reason it's not working, the value for the neutered button isn't passed from the database (it stays empty) and when i physically press the one of the neutered/not neutered button the app restarts, value stays empty and when i view the profile under neutered it says "unspecified". i'll edit the original question so you could see
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.