You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Firebase获取用户信息时出现SPAN_EXCLUSIVE_EXCLUSIVE错误求助

问题分析与修复方案

首先,咱们先搞定那个烦人的SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero-length错误,再梳理代码和布局里的坑,最后给你落地的修复步骤:

一、错误的直接诱因

这个错误说白了就是TextView拿到了空字符串或者只有空白的内容,Android的文本处理系统对这种情况会抛出异常。结合你的情况来看:

  • 布局里的TextView引用了strings.xml里那种只填了空格的资源(比如textviewGenderDb),页面一加载就可能触发这个问题;
  • 从Firebase取数据时,有的用户字段缺失(比如Ana没有gender),反序列化后这个字段是null,你直接塞到列表里,ListView的Item就会显示空内容,进而触发错误。

二、代码和布局里的核心问题

1. 逻辑跑偏:加载了所有用户而非当前登录用户

你现在的代码监听的是整个User节点,然后遍历所有用户的数据,但你要的明明是当前登录用户的信息啊!这不仅会加载无关数据,还会导致列表里塞了一堆不属于当前用户的内容,完全不符合需求。

2. 布局和代码不匹配

你说布局里有多个TextView,但代码里却用ListView来展示数据,这明显驴唇不对马嘴:要么用ListView/RecyclerView来列表展示每个字段,要么用单个TextView对应每个用户属性(比如用户名、年龄各占一个TextView),现在的写法完全浪费了布局里的TextView。

3. 没处理空字段

Firebase里的用户数据有缺失(比如Ana的gender字段不存在),用ds.getValue(User.class)反序列化时,缺失的字段会变成null,你直接把null加到列表里,就会导致TextView显示空内容,触发SPAN错误。

三、一步步修复

第一步:修正数据获取逻辑,只拿当前用户的数据

把监听整个User节点改成直接定位到当前登录用户的UID节点,别再遍历所有用户了:

// 替换原来的数据库引用和监听逻辑
databaseReference = FirebaseDatabase.getInstance().getReference();
// 直接指向当前用户的专属节点
DatabaseReference currentUserRef = databaseReference.child("User").child(userId);

ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        itemList.clear(); // 先清空列表,防止重复加载
        if(dataSnapshot.exists()){
            User currentUser = dataSnapshot.getValue(User.class);
            // 给每个字段加null判断,用默认值替代空值
            itemList.add("用户名: " + (currentUser.getUsername() != null ? currentUser.getUsername() : "未设置"));
            itemList.add("年龄: " + (currentUser.getAge() != null ? currentUser.getAge() : "未设置"));
            itemList.add("体重: " + (currentUser.getWeight() != null ? currentUser.getWeight() : "未设置"));
            itemList.add("身高: " + (currentUser.getHeight() != null ? currentUser.getHeight() : "未设置"));
            itemList.add("性别: " + (currentUser.getGender() != null ? currentUser.getGender() : "未设置"));
        } else {
            itemList.add("未找到用户信息");
        }
        arrayAdapter = new ArrayAdapter<>(AccountActivity.this, android.R.layout.simple_list_item_1, itemList);
        myListView.setAdapter(arrayAdapter);
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        // 别忽略错误,至少打个日志方便排查
        Log.e("AccountActivity", "数据库读取失败: " + databaseError.getMessage());
    }
};
currentUserRef.addListenerForSingleValueEvent(valueEventListener);

第二步:对齐布局和代码的逻辑

如果你的布局是用多个TextView分别展示每个属性(比如用户名TextView、年龄TextView),那应该直接把数据绑定到对应TextView,而不是用ListView:
比如activity_account.xml可以改成这样:

<TextView
    android:id="@+id/tv_username"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="用户名:" />
<TextView
    android:id="@+id/tv_age"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="年龄:" />
<!-- 体重、身高、性别对应的TextView同理 -->

然后代码里改成这样:

// 初始化各个TextView
TextView tvUsername = findViewById(R.id.tv_username);
TextView tvAge = findViewById(R.id.tv_age);
TextView tvWeight = findViewById(R.id.tv_weight);
TextView tvHeight = findViewById(R.id.tv_height);
TextView tvGender = findViewById(R.id.tv_gender);

// 在onDataChange里绑定数据
if(dataSnapshot.exists()){
    User currentUser = dataSnapshot.getValue(User.class);
    tvUsername.setText("用户名: " + (currentUser.getUsername() != null ? currentUser.getUsername() : "未设置"));
    tvAge.setText("年龄: " + (currentUser.getAge() != null ? currentUser.getAge() : "未设置"));
    tvWeight.setText("体重: " + (currentUser.getWeight() != null ? currentUser.getWeight() : "未设置"));
    tvHeight.setText("身高: " + (currentUser.getHeight() != null ? currentUser.getHeight() : "未设置"));
    tvGender.setText("性别: " + (currentUser.getGender() != null ? currentUser.getGender() : "未设置"));
}

同时,把strings.xml里那些只含空格的资源删掉,初始文本直接用"未设置"或者在代码里初始化就行。

第三步:彻底解决空值问题

不管用ListView还是单个TextView,一定要对每个字段做null判断,用默认值(比如"未设置")替代null,这样就不会把空内容传给TextView,从根源上解决SPAN错误。

额外的优化建议

  • 别忽略onCancelled回调,加个日志打印,万一数据库权限不对或者连接失败,能快速定位问题;
  • 给Firebase数据库设置合理的安全规则,确保只有当前用户能读写自己的信息:
{
  "rules": {
    "User": {
      "$uid": {
        ".read": "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      }
    }
  }
}

这样既安全,也能避免读取到其他用户的数据。

内容的提问来源于stack exchange,提问作者Denisa Mărginean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 22:43:14