我想从firebase实时数据库中显示recyclerview android上的数据..但我无法将动态数据加载到适配器数组中

Posted

技术标签:

【中文标题】我想从firebase实时数据库中显示recyclerview android上的数据..但我无法将动态数据加载到适配器数组中【英文标题】:I want to show data on recyclerview android from firebase realtime database.. but i am unable to load dynamic data into adapter array 【发布时间】:2021-10-07 01:07:55 【问题描述】:

我想在 android 的 recyclerview 中显示数据。数据将从 Firebase 实时数据库中检索,但我遇到了一个奇怪的问题。

为了从数据库中获取所需的数据,我想在两个不同的节点读取数据库两次。

我在下面附上了我的代码,以及数据结构的可视化概览。

RecyclerView 只显示演示值,它被硬编码到适配器数组中。它没有显示应该从 for 循环内部添加的数据。

请注意:我的适配器和助手都是正确的。

我在下面附上了我的代码:

`

package com.example.attendx;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
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.ValueEventListener;

import java.util.ArrayList;

public class dashboard extends AppCompatActivity 

    RecyclerView featuredrecycler;
    RecyclerView.Adapter adapter;

    ArrayList<FeaturedHelper> admin_cls = new ArrayList<FeaturedHelper>();


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dashboard);

        //Hooks Recycler view
        featuredrecycler = findViewById(R.id.featured_recycler);
        DatabaseReference Root_Ref, UserProfile_Ref;
        Root_Ref = FirebaseDatabase.getInstance().getReference();
        UserProfile_Ref = Root_Ref.child("userprofile").child(uid);

        DatabaseReference User_Sir_ji_Ref;
        User_Sir_ji_Ref = UserProfile_Ref.child("Sir_ji");

        //method created for recycler view
        featuredrecycler(User_Sir_ji_Ref, Root_Ref);

    

    private void featuredrecycler(DatabaseReference user_Sir_ji_Ref, DatabaseReference root_Ref) 

        featuredrecycler.setHasFixedSize(true);
        featuredrecycler.setLayoutManager(new LinearLayoutManager(dashboard.this, LinearLayoutManager.HORIZONTAL, false));


        //ArrayList<FeaturedHelper> admin_cls = new ArrayList<>();

        admin_cls.add(new FeaturedHelper(R.drawable.icon, "test0", "test2")); // This DEMO SHOWS


        user_Sir_ji_Ref = user_Sir_ji_Ref;
        user_Sir_ji_Ref.addListenerForSingleValueEvent(new ValueEventListener() 
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) 

                if(snapshot.exists())
                    DatabaseReference ClassHeader;
                    ClassHeader = root_Ref.child("clas-s-room_header");
                    for(DataSnapshot snapshot1 : snapshot.getChildren())

                        Log.d("SNAPSHOT", snapshot1.getValue().toString());

                        ClassHeader.child(snapshot1.getValue().toString()).addListenerForSingleValueEvent(new ValueEventListener() 


                            @Override
                            public void onDataChange(@NonNull DataSnapshot snapshot) 
                                String Cls_name, createdBy;
                                Cls_name = snapshot.child("ClassName").getValue().toString();
                                createdBy = snapshot.child("TeacherName").getValue().toString();

                                admin_cls.add(new FeaturedHelper(R.drawable.icon, Cls_name, createdBy)); // THIS DOESNOT SHOWS

                                Log.d("SNAPSHOT", Cls_name+"\n"+createdBy);

                            

                            @Override
                            public void onCancelled(@NonNull DatabaseError error) 

                                Toast.makeText(getApplicationContext(), "Recycler View Error.", Toast.LENGTH_SHORT).show();

                            
                        );

                    
                

            


            @Override
            public void onCancelled(@NonNull DatabaseError error) 

                Toast.makeText(getApplicationContext(), "UNABLE_TO_READ_SIR_JI", Toast.LENGTH_SHORT).show();
            
        );


        Log.d("SNAPSHOT", admin_cls.toString()); // HERE IT SHOWS ONLY ONE ELEMENT 
        adapter = new FeaturedAdapter(admin_cls);
        featuredrecycler.setAdapter(adapter);

    

`

请帮我解决这个奇怪的问题。

数据库结构见以下链接:

userprofile node has sir_ji node inside, which has class_id

class_header node has node of class_id, which contains class details

【问题讨论】:

你能分享你的json数据库吗? 是的,请稍等片刻......但我想提一下,使用日志我已经验证我在 Cls_name 和 for 循环中的 createdBy 变量中获得了所需的值 那么你想得到的确切数据是什么,按什么顺序?请回复@AlexMamo 【参考方案1】:

Firebase 以异步方式工作,您应该将代码放在方法onDataChange 中。由于您使用的是 for loop 并在其中连接 Firebase,因此您可以在检索值时为其创建延迟。

for(DataSnapshot snapshot1 : snapshot.getChildren())
   Log.d("SNAPSHOT", snapshot1.getValue().toString());
   //Here your all codes...

//Here you call the this function.
//1000 = 1 second
CreateDelay(1000, () -> 
   Log.d("SNAPSHOT", admin_cls.toString());
   adapter = new FeaturedAdapter(admin_cls);
   featuredrecycler.setAdapter(adapter);
);

方法CreateDelay及其接口

public static void CreateDelay(final long delayMillis, @NonNull final DelayCallback delayCallback) 
    final Looper l = Looper.myLooper();
    if (l != null) 
        new Handler(l).postDelayed(delayCallback::onFinished, delayMillis);
    


@FunctionalInterface
public interface DelayCallback 
    void onFinished();

【讨论】:

谢谢,但所有代码都意味着在其中创建数组或像之前一样向数组添加值?? 对不起,我不明白你的问题@MillenniumChowdhury 如果您看到我之前的代码,我已经在 ondatachange 内的数组中添加了值...但是在 ondata change 适配器之外设置了适配器 = new FeaturedAdapter(admin_cls); featuresrecycler.setAdapter(适配器);现在我应该在 ondatachanged 中定义数组并设置适配器 @MillenniumChowdhury 是的,你可以试试我的答案,在onDataChange中定义它【参考方案2】:

当您更改 admin_cls 中的数据时,您需要告诉适配器该事实,以便它知道重新呈现视图。

每当您对admin_cls 中的数据进行更改(或完成更改)时,您都可以通过调用adapter.notifyDataSetChanged() 来执行此操作。

user_Sir_ji_Ref.addListenerForSingleValueEvent(new ValueEventListener() 
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) 
        if(snapshot.exists())
            DatabaseReference ClassHeader;
            ClassHeader = root_Ref.child("clas-s-room_header");
            for(DataSnapshot snapshot1 : snapshot.getChildren())
                ClassHeader.child(snapshot1.getValue().toString()).addListenerForSingleValueEvent(new ValueEventListener() 
                    @Override
                    public void onDataChange(@NonNull DataSnapshot snapshot) 
                        String Cls_name, createdBy;
                        Cls_name = snapshot.child("ClassName").getValue().toString();
                        createdBy = snapshot.child("TeacherName").getValue().toString();

                        admin_cls.add(new FeaturedHelper(R.drawable.icon, Cls_name, createdBy));

                        adapter.notifyDataSetChanged(); // ? Add this
                    

【讨论】:

以上是关于我想从firebase实时数据库中显示recyclerview android上的数据..但我无法将动态数据加载到适配器数组中的主要内容,如果未能解决你的问题,请参考以下文章

Recycler View 不显示数据

如何使用颤振从firebase实时检索数据

如何将Firebase Recycler视图从最新(列表顶部)排序到最旧[重复]

读取 longlat 数据实时 Firebase 和实现以映射 Android Studio

如何在 Fragment 中使用 Recycler View [重复]

我想使用 GeoFire 在 android 中填充 Firebase Recycler View