如何根据 Firebase 实时数据库中的“设备”子项在 RecyclerView 中显示数据“用户设备”设备名称

Posted

技术标签:

【中文标题】如何根据 Firebase 实时数据库中的“设备”子项在 RecyclerView 中显示数据“用户设备”设备名称【英文标题】:How to show data "user_devices" device_name in RecyclerView based on "devices" child from Firebase Realtime Database 【发布时间】:2021-01-21 04:52:43 【问题描述】:

这是我的 Firebase 实时数据库示例


  "devices": 
    "123456": 
      "device_mac_id": "123456",
      "device_name": "BOX 12",
      "id": "2"
    ,
    "222222": 
      "device_mac_id": "222222",
      "device_name": "BOX 22",
      "id": "3"
    ,
    "888888": 
      "device_mac_id": "888888",
      "device_name": "BOX 88",
      "id": "6"
    
  ,
  "users": 
    "UcI1REoXAoSC7mg4u7RGbw8gR2g2": 
      "email_id": "ab@cd.com",
      "full_name": "Ab Cd",
      "id": "UcI1REoXAoSC7mg4u7RGbw8gR2g2",
      "user_devices": 
        "-MIbRGtT25ki36foJ6b5": "888888",
        "-MIc-ORsWRqO45OJrBXg": "123456"
      
    
  

DashboardFragment.java


    showProgressBar();

    deviceModelArrayList.clear();
    devicesAdapter.notifyDataSetChanged();

    mDatabaseRef
            .child("users")
            .child(FirebaseAuth.getInstance().getUid())
            .child("user_devices")
            .orderByKey()
            .addChildEventListener(
                    new ChildEventListener() 
                        @Override
                        public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) 
                            Log.e(TAG,
                                    "onChildAdded:"
                                            + " snapshot:" + snapshot.getValue()
                                            + " previousChildName:" + previousChildName);
                            getDeviceData(snapshot.getValue(String.class));
                        

                        @Override
                        public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) 
                            Log.e(TAG,
                                    "onChildChanged:"
                                            + " snapshot:" + snapshot.getValue()
                                            + " previousChildName:" + previousChildName);
                        

                        @Override
                        public void onChildRemoved(@NonNull DataSnapshot snapshot) 
                            Log.e(TAG,
                                    "onChildRemoved:"
                                            + " snapshot:" + snapshot.getValue());
                        

                        @Override
                        public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) 
                            Log.e(TAG,
                                    "onChildMoved:"
                                            + " snapshot:" + snapshot.getValue()
                                            + " previousChildName:" + previousChildName);
                        

                        @Override
                        public void onCancelled(@NonNull DatabaseError error) 
                            Log.e(TAG,
                                    "onCancelled:"
                                            + " error:" + error.toString());
                        
                    );



private void getDeviceData(String deviceID) 
    if (deviceID != null) 
        mDatabaseRef
                .child("devices")
                .child(deviceID)
                .addListenerForSingleValueEvent(
                        new ValueEventListener() 
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) 
                                hideProgressBar();

                                // This method is called once with the initial value and again
                                // whenever data at this location is updated.
                                UserModel.DeviceModel deviceModel = dataSnapshot.getValue(UserModel.DeviceModel.class);
                                Log.e(TAG, "onDataChange: devices: " + deviceModel.getDevice_name());

                                deviceModelArrayList.add(deviceModel);
                                devicesAdapter.notifyDataSetChanged();
                            

                            @Override
                            public void onCancelled(DatabaseError error) 
                                hideProgressBar();
                                // Failed to read value
                                Log.w(TAG, "Failed to read value.", error.toException());
                            
                        
                );
    

我想在 RecyclerView 中显示,但随着 onDataChanged 数据不断增加,我正在向 ArrayList 添加对象。如果我错了或最佳做法,请建议我。

【问题讨论】:

为了更好理解,需要从users->uid->user_devices获取用户设备,其实是两个,888888和123456,根据这些值,需要获取@中存在的设备对象987654324@,对吧? @Alex 是的,有 3 台设备,但我只为用户分配了 2 台。 【参考方案1】:

根据你上一条评论:

是的,有 3 台设备,但我只为用户分配了 2 台。

要获取只对应特定用户的DeviceModel对象,需要使用getChildren()方法循环DataSnapshot对象两次,如下代码行所示:

String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference userDevicesRef = rootRef.child("users").child(uid).child("user_devices");
ValueEventListener valueEventListener = new ValueEventListener() 
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) 
        for(DataSnapshot userDeviceSnapshot : dataSnapshot.getChildren()) 
            String deviceId = userDeviceSnapshot.getValue(String.class);
            DatabaseReference userDevicesRef = rootRef.child("devices").child(deviceId);
            ValueEventListener eventListener = new ValueEventListener() 
                @Override
                public void onDataChange(DataSnapshot deviceSnapshot) 
                    UserModel.DeviceModel deviceModel = dataSnapshot.getValue(UserModel.DeviceModel.class);
                    Log.d("TAG", deviceModel.getDevice_name());
                

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) 
                    Log.d("TAG", databaseError.getMessage()); //Don't ignore potential errors!
                
            ;
            userDevicesRef.addListenerForSingleValueEvent(eventListener);
        
    

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) 
        Log.d("TAG", databaseError.getMessage()); //Don't ignore potential errors!
    
;
userDevicesRef.addListenerForSingleValueEvent(valueEventListener);

logcat 中的结果将是:

BOX 88
BOX 12

但这只是为了看到它正在工作。在您的情况下,您应该将这些对象添加到列表中并通知适配器有关更改。

【讨论】:

谢谢伙计。您的回答很周到,但我的挑战是处理列表。我找到了解决方案并在这里回答。【参考方案2】:

感谢@Alex 及时回复。

在等待答案的同时,我对FirebaseUI for Realtime Database做了一些研究

dependencies 
// FirebaseUI for Firebase Realtime Database
implementation 'com.firebaseui:firebase-ui-database:x.y.z'

我对 FirebaseRecyclerAdapter 感觉更舒服,因为我的挑战是处理列表。

这是我的代码 sn-ps 对我有用。

firebaseRecyclerOptions =
            new FirebaseRecyclerOptions
                    .Builder<String>()
                    .setQuery(mDatabaseRef.child("users").child(mFirebaseAuth.getUid()).child("user_devices"), String.class)
                    .build();

    firebaseRecyclerAdapter =
            new FirebaseRecyclerAdapter<String, DevicesViewHolder>(firebaseRecyclerOptions) 

                @Override
                protected void onBindViewHolder(@NonNull DevicesViewHolder holder, int position, @NonNull String deviceID) 
                    if (deviceID != null) 
                        mDatabaseRef
                                .child("devices")
                                .child(deviceID)
                                .addListenerForSingleValueEvent(
                                        new ValueEventListener() 
                                            @Override
                                            public void onDataChange(DataSnapshot dataSnapshot) 
                                                hideProgressBar();

                                                // This method is called once with the initial value and again
                                                UserModel.DeviceModel deviceModel = dataSnapshot.getValue(UserModel.DeviceModel.class);
                                                Log.e(TAG, "onDataChange: devices: " + deviceModel.getDevice_name());

                                                holder.b.btnPowerBox.setText(deviceModel.getDevice_name());
                                            

                                            @Override
                                            public void onCancelled(DatabaseError error) 
                                                hideProgressBar();
                                                // Failed to read value
                                                Log.w(TAG, "Failed to read value.", error.toException());
                                            
                                        
                                );
                    

                    holder.b.btnPowerBox.setOnClickListener(view -> 
                        Log.d(TAG, "onBindViewHolder: Button clicked at position " + position);
                    );
                

                @NonNull
                @Override
                public DevicesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
                    ItemDevicesBinding bItem = ItemDevicesBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
                    return new DevicesViewHolder(bItem);
                

                @Override
                public void onDataChanged() 
                    // If there are no chat messages, show a view that invites the user to add an item to list.
                    b.tvEmptyListMessage.setVisibility(getItemCount() == 0 ? View.VISIBLE : View.GONE);
                
            ;
    firebaseRecyclerAdapter.startListening();
    b.rvDevices.setAdapter(firebaseRecyclerAdapter);

【讨论】:

以上是关于如何根据 Firebase 实时数据库中的“设备”子项在 RecyclerView 中显示数据“用户设备”设备名称的主要内容,如果未能解决你的问题,请参考以下文章

如何根据特定时间删除 Firebase 数据库中的项目

如何根据 Firebase 分析中的总收入分析设备和操作系统分布?

如何实现一个 Firebase 监听器来观察数据库的实时变化

如何根据 Firebase 数据库中的条目向我的 android 应用发送通知? [关闭]

如何使用 Cloud Functions for Firebase 更新 Firebase 实时数据库中的值

如何从firebase实时数据库中删除?