【问题标题】:how to retrieve value of a radio button back from firebase database android如何从firebase数据库android中检索单选按钮的值
【发布时间】:2021-03-11 13:11:46
【问题描述】:

大家好,我是新来的,也是安卓开发的新手, 首先,如果之前有人问过并回答过,我想道歉。 我正在尝试构建一个 android 应用程序,在用户个人资料中,我有 2 个用于性别、男性和女性的单选按钮。 我能够将所选单选按钮的值传递给 firebase 数据库。 这是我使用的代码:

    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);

这用于单选按钮选择

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

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

我能够将性别值作为文本传回用户个人资料屏幕

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);
            }

当我转到编辑用户配置文件时,正确的单选按钮显示为选中,但是当我单击保存配置文件时,应用程序崩溃,就像没有选中单选按钮时一样。 如果我在编辑个人资料页面中重新单击相同的单选按钮,一切正常。

我怎样才能修复它,这样用户就不必重新单击单选按钮(除非他想更改选择),并且在保存配置文件时它会将该按钮识别为已选中?

我认为问题在于,当将单选按钮值传递给数据库时,使用了“radioBtnDogGender”,而当从数据库传回值时,使用了“radioBtmMale”/“radioBtnFemale”。

如何将值传递到“radioBtnDogGender”而不是特定的男性/女性单选按钮?

这是xml代码:

<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>

这是应用程序崩溃时的堆栈跟踪(按下保存配置文件而不重新单击单选按钮):

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)

正如我在 cmets 中提到的,Gender 单选按钮在新代码中运行良好,当我尝试对 Neutered 单选按钮实现相同的代码时,我遇到了一个新问题,Neutered 单选按钮保持空白,当我物理按下时在其中一个上,应用程序重新启动,同时将 Neutered 单选按钮留空,在 Neutered 下的 View profile 中显示“未指定” 这是 Gender 和 Neutered 单选按钮的代码

            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();
    }
}

我是不是忘记了什么,或者 Neutered 单选按钮需要不同的代码?

【问题讨论】:

  • 如果应用程序崩溃,会有一个堆栈跟踪。请在 logcat 上查找,并将其添加到您的问题中。

标签: java android firebase google-cloud-firestore


【解决方案1】:

首先,在您的onEvent 处理程序中,您忽略了error 的值,这可能会导致您在尝试访问null 的潜在null 值时崩溃valueonEvent 处理程序的第一行应检查侦听器是否失败。

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

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

错误也可能来自以下几行:

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

当您的用户第一次加载他们的个人资料时,dogGender 的值可能是 null。当它是null 时,您尝试调用null.equalsIgnoreCase(...),这将抛出NullPointerException。相反,您应该先检查它是否为null,然后再将其与FemaleMale 进行比较。此外,当以编程方式更改当前选中的单选按钮时,它不会调用 radioBtnGenderClick 侦听器,这意味着 radioBtnDogGender 不会更新 - 所以我们在这里更新。

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;
}

虽然我一直在输入此内容,但现在您已经为错误提供了堆栈跟踪,我们实际上可以看到导致错误的行是:

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

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

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

如上所述,当您使用 setChecked() 更新选定的单选按钮时,不会调用 radioBtnGenderClick 侦听器,因此 radioGroupDogGender 可能是 null,直到用户单击性别选项之一,除非您应用更改以上手动设置radioBtnDogGender。当在radioGroupDogGender 中没有主动选择的单选按钮时执行radioBtnGenderClick 侦听器,radioGroupDogGender.getCheckedRadioButtonId() 返回值-1。在下一行,您调用findViewById(-1),然后将radioBtnDogGender 的值设置为null。之后,您有效地调用((RadioButton) null).getText(),它会抛出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();
    }
}

同样,您还假设radioBtnDogGendersaveUserProfile 按钮的onClickListener 中不是null

String dogGender = radioBtnDogGender != null ? radioBtnDogGender.getText().toString() : "Unspecified";

【讨论】:

  • 作为附录,我还将重新考虑您的数据库结构,以便您可以容纳拥有多条狗的用户。 /users/{uid} 是所有者,/dogs/{dogId}(或/users/{uid}/dogs/{dogId})是关于狗的信息(带有owner = "someUID" 属性)
  • 首先感谢您的回答。当从数据库中调用该值时,正确的单选按钮 (radioBtnMale/radioBtnFemale) 显示为已选中。正如您提到的,radioBtnDogGender 没有被主动选择,我该如何解决这个问题,radioBtnDogGender 将自动被选择,并从数据库中恢复相关选择?关于您对每个用户多只狗的建议,目前我想专注于每个用户一只狗,将来我可能会添加多只狗的选项
  • 就在String gender = ...之前,尝试添加radioGroupDogGender.clearCheck();
  • 我尝试了 clearCheck,不幸的是我得到了相同的结果,可见单选按钮被选中但它没有填充 radioBtnDogGender 值并且它保持为空,有没有办法传递值radioBtnMale/Female 改成 radioBtnDogGender?
  • 谢谢,狗的性别工作正常,它从数据库中获取值,并且当我保存配置文件而不实际按下/重新按下性别单选按钮时不会崩溃。我试图对绝育单选按钮实现相同的代码,但由于某种原因它不起作用,绝育按钮的值没有从数据库传递(它保持为空)并且当我物理按下一个绝育/不绝育按钮应用程序重新启动,值保持为空,当我查看绝育下的配置文件时,它显示“未指定”。我将编辑原始问题,以便您查看
猜你喜欢
  • 2013-03-19
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多