在我的数组有任何元素之前调用Firebase-Adapter,并返回一个空的RecyclerView



我遇到了一个非常奇怪的问题,我在数据库中调用了两个节点,从一个节点我获得了所有的用户ID,然后我只在用户节点内循环以获得用户元数据。问题是,当我运行调试器时,似乎在获取数据之前调用了mAdapter。所以我的适配器在没有数据的情况下设置了回收视图。在调用适配器之后,我的获取用户的查询开始,数组被正常填充

这就是我到目前为止所做的

mDatabase.child("teamsNode").child(teamID).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot snapshot : dataSnapshot.getChildren()){
mDatabase.child("users").child(snapshot.getKey()).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
UserModel model = dataSnapshot.getValue(UserModel.class);
String playerName = model.getName();
model.setName(playerName);
mArrayPlayers.add(model);
}

@Override
public void onCancelled(@NonNull DatabaseError databaseError) { }
});
}
mAdapter = new PlayersAdapter(mArrayPlayers,mContext,R.layout.recycler_row);
if(mAdapter.getItemCount()>0)
mRecyclerView.setAdapter(mAdapter);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) { }
});

正如你所看到的,我在获取所有数据的第一个foreach之后将适配器设置为recyclerview,我知道在异步的情况下,我需要等待内部mDatabase完成,但如果我将适配器的设置移到上面一行,等待第二个调用完成,它也会这样做,知道吗?

数据库结构类似于

teamsNode
|__Jm2KSMjslpow2Ipoasz : true
|__601KSMjsldfjd2Ipos0 : true
|__asgm2Kshalpow2IposJ : true
users
|__Jm2KSMjslpow2Ipoasz 
|_____name: randomname1
|__601KSMjsldfjd2Ipos0
|_____name: randomname2
|__asgm2Kshalpow2IposJ
|_____name: randomname3

Recyclerview未填充。知道吗?

奇怪的是,有时用调试器运行它确实会填充数据,但这种情况很少发生。

如果只想在加载所有数据时初始化适配器,则需要在嵌套的onDataChange回调中进行初始化:

mDatabase.child("teamsNode").child(teamID).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshotTeam) {
AtomicInteger loadedUserCount = new AtomicInteger(0);
for(DataSnapshot snapshot : dataSnapshotTeam.getChildren()){
mDatabase.child("users").child(snapshot.getKey()).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
UserModel model = dataSnapshot.getValue(UserModel.class);
String playerName = model.getName();
model.setName(playerName);
mArrayPlayers.add(model);
if (loadedUserCount.getAndIncrement() + 1 == dataSnapshotTeam.getChildrenCount()) {
mAdapter = new PlayersAdapter(mArrayPlayers,mContext,R.layout.recycler_row);
if(mAdapter.getItemCount()>0) {
mRecyclerView.setAdapter(mAdapter);
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) { 
throw databaseError.toException(); // don't ignore errors
}
});
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) { 
throw databaseError.toException(); // don't ignore errors
}
});

问题是对addListenerForSingleValueEvent方法的调用是异步的,因此它们在另一个线程中执行。当您调用第二个addListenerForSingleValueEvent时,它在另一个线程中执行,而主线程跟随它的执行。您必须在onDataChange方法中的第二个调用addListenerForSingleValueEvent的应答中执行适配器的调用。这样可以避免应用程序的异常操作。

希望这会有所帮助。

mDatabase.child("teamsNode").child(teamID).addListenerForSingleValueEvent(new ValueEventListener() {
mArrayPalyer.clear();//add this
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot snapshot : dataSnapshot.getChildren()){
mDatabase.child("users").child(snapshot.getKey()).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
UserModel model = dataSnapshot.getValue(UserModel.class);
String playerName = model.getName();
model.setName(playerName);
mArrayPlayers.add(model);
}

@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
mAdapter = new PlayersAdapter(mArrayPlayers,mContext,R.layout.recycler_row);
mRecyclerView.setAdapter(mAdapter); //makes changes here because you are checking for adapter item count before setting it and this always return null.
}

您可以查看我的代码,我和您一样使用ValueEventListener,并将数据绑定到recycler view

ValueEventListener postListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()){
UserListModel userListModel =dataSnapshot1.getValue(UserListModel.class);
userModelArrayList.add(userListModel);
}
userListAdapter.notifyDataSetChanged();
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(">>value", "loadPost:onCancelled", databaseError.toException());
}
};
//mDatabase is the reference to the Firebase Node
mDatabase.addValueEventListener(postListener);
userListRecyclerView.setLayoutManager(M.gridLayoutRecyclerView(getActivity() , 2));
userListAdapter = new UserListAdapter(getActivity(), userModelArrayList);
userListRecyclerView.setAdapter(userListAdapter);

最新更新