Android ForumAdapter失效,RecyclerView无搜索结果显示求助
我开发了一款类论坛Android应用,用户可发布论坛(问题)并接收其他用户回复,功能类似Stack Overflow。我构建的ForumAdapter用于关联RecyclerView,展示用户搜索到的论坛内容,但搜索已存在的论坛后,RecyclerView中无任何内容显示,尝试多种方案、教程及网络搜索均未解决,寻求问题原因及解决办法。
适配器代码
package com.example.mathmate.Adapters; import android.content.Context; import android.net.Uri; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.example.mathmate.Models.Forum; import com.example.mathmate.Models.User; import com.example.mathmate.R; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.Query; import com.google.firebase.database.ValueEventListener; import java.util.List; public class ForumAdapter extends RecyclerView.Adapter<ForumAdapter.ViewHolder> { private Context context; private List<Forum> forums; public ForumAdapter(Context context, List<Forum> forums) { this.context = context; this.forums = forums; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View v = LayoutInflater.from(context).inflate(R.layout.search_forum_row, parent, false); return new ForumAdapter.ViewHolder(v); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { final Forum forum = forums.get(position); holder.title.setText(forum.getTitle()); holder.subject.setText(forum.getSubject()); DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Registered Users"); Query query = reference.orderByValue().equalTo(forum.getAuthorUid()); query.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { for (DataSnapshot dataSnapshot : snapshot.getChildren()) { User user = dataSnapshot.getValue(User.class); assert user != null; Uri uriImage = Uri.parse(user.getUri()); Glide.with(context).load(uriImage).placeholder(R.drawable.default_pfp).into(holder.profilePicture); } } @Override public void onCancelled(@NonNull DatabaseError error) { } }); holder.itemView.setOnClickListener(v -> { // TODO : move the user to the forum activity }); } @Override public int getItemCount() { return 0; } public class ViewHolder extends RecyclerView.ViewHolder { public TextView title, subject; public ImageView profilePicture; public ViewHolder(@NonNull View itemView) { super(itemView); title = itemView.findViewById(R.id.title_et); subject = itemView.findViewById(R.id.subject_et); profilePicture = itemView.findViewById(R.id.profile_picture); } } }
Fragment代码
package com.example.mathmate.Fragments; import android.os.Bundle; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.RecyclerView; import com.example.mathmate.Adapters.ForumAdapter; import com.example.mathmate.Models.Forum; import com.example.mathmate.R; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.Query; import com.google.firebase.database.ValueEventListener; import java.util.ArrayList; import java.util.List; import java.util.Locale; public class ForumsFragment extends Fragment { // widgets private EditText search_bar; private RecyclerView recyclerView; // vars private List<Forum> mForumList; private DatabaseReference database; private ForumAdapter adapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View v = inflater.inflate(R.layout.fragment_forums, container, false); search_bar = v.findViewById(R.id.search_bar); database = FirebaseDatabase.getInstance().getReference("Forums"); recyclerView = v.findViewById(R.id.recyclerView); initTextListener("title"); return v; } private void initTextListener(String parameter) { mForumList = new ArrayList<>(); search_bar.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { String text = search_bar.getText().toString().toLowerCase(Locale.getDefault()); searchForMatch(text, parameter); } }); } private void searchForMatch(String keyword, String parameter) { mForumList.clear(); if (TextUtils.isEmpty(keyword)) { ReadAllUsers(); } else { Query query = database.orderByChild(parameter).startAt(keyword); query.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { for (DataSnapshot dataSnapshot : snapshot.getChildren()) { mForumList.add(dataSnapshot.getValue(Forum.class)); updateForumList(); } } @Override public void onCancelled(@NonNull DatabaseError error) { } }); } } private void ReadAllUsers() { database.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { for (DataSnapshot dataSnapshot : snapshot.getChildren()) { Forum forum = dataSnapshot.getValue(Forum.class); mForumList.add(forum); } updateForumList(); } @Override public void onCancelled(@NonNull DatabaseError error) { } }); } private void updateForumList() { adapter = new ForumAdapter(getContext(), mForumList); recyclerView.setAdapter(adapter); } }
XML布局代码
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/darkBG" tools:context=".Fragments.ForumsFragment"> <LinearLayout android:id="@+id/linearLayout7" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:gravity="center" android:orientation="horizontal" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:ignore="UselessParent"> <EditText android:id="@+id/search_bar" android:layout_width="325dp" android:layout_height="48dp" android:layout_weight="1" android:autofillHints="" android:background="@drawable/corner_radius" android:ems="10" android:hint="@string/search" android:inputType="text" android:paddingStart="5dp" android:text="" android:textColor="@color/white" android:textColorHint="#9C9C9C" android:textSize="13sp" tools:ignore="RtlSymmetry" /> <ImageButton android:id="@+id/search_btn" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="10dp" android:layout_weight="1" android:background="@drawable/corner_radius" android:backgroundTint="@color/darkBG" android:contentDescription="@string/todo" android:src="@drawable/search" /> </LinearLayout> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="5dp" android:layout_marginTop="15dp" android:layout_marginEnd="5dp" android:layout_weight="1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/linearLayout7" tools:listitem="@layout/search_forum_row" /> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> </ScrollView> </androidx.constraintlayout.widget.ConstraintLayout>
问题原因及解决办法
1. 适配器getItemCount()返回值错误
ForumAdapter中getItemCount()固定返回0,RecyclerView无法获取列表项数量,导致无内容渲染。
修复:
@Override public int getItemCount() { return forums != null ? forums.size() : 0; }
2. RecyclerView未设置LayoutManager
ForumsFragment中未给RecyclerView设置布局管理器,无法确定列表项的布局方式。
修复:
在onCreateView中添加:
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
3. 搜索逻辑大小写不匹配
搜索时将输入转为小写,但Firebase查询大小写敏感,若数据库中title为大写或混合格式,无法匹配结果。
修复:
存储论坛数据时新增titleLower字段(存储小写标题),查询时修改为:
Query query = database.orderByChild("titleLower").startAt(keyword).endAt(keyword + "\uf8ff");
4. 查询循环中重复更新适配器
searchForMatch的onDataChange里,每次添加数据后都调用updateForumList(),导致重复创建适配器,数据加载异常。
修复:
将updateForumList()移到循环外部:
@Override public void onDataChange(@NonNull DataSnapshot snapshot) { mForumList.clear(); for (DataSnapshot dataSnapshot : snapshot.getChildren()) { mForumList.add(dataSnapshot.getValue(Forum.class)); } updateForumList(); }
5. ScrollView遮挡RecyclerView
布局中空ScrollView覆盖整个屏幕,导致RecyclerView被遮挡无法显示。
修复:
移除多余的ScrollView及其内部LinearLayout,RecyclerView本身支持滚动。同时修改RecyclerView的高度约束:
<androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginStart="5dp" android:layout_marginTop="15dp" android:layout_marginEnd="5dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/linearLayout7" tools:listitem="@layout/search_forum_row" />
6. 用户查询逻辑错误
ForumAdapter中查询用户时使用orderByValue(),但用户节点的键应为UID,正确方式是直接通过UID获取节点。
修复:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Registered Users").child(forum.getAuthorUid()); reference.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { User user = snapshot.getValue(User.class); if (user != null) { Uri uriImage = Uri.parse(user.getUri()); Glide.with(context).load(uriImage).placeholder(R.drawable.default_pfp).into(holder.profilePicture); } } @Override public void onCancelled(@NonNull DatabaseError error) { } });
内容的提问来源于stack exchange,提问作者Bazinga

