【问题标题】:Android Firebase how to loop through EVERY key of the listAndroid Firebase如何遍历列表的每个键
【发布时间】:2018-05-03 21:44:23
【问题描述】:

在 Firebase 实时数据库中,我为每个列表项创建了一个具有唯一键的列表。

String deviceId = dbDevice.push().getKey();
dbDevice.child(deviceId).setValue(device);

在另一个 Activity 中,我想按键循环遍历每个设备,并为每个特定设备调用方法 updateLatestDistance。

虽然下面代码的结果以一种奇怪的方式运行。 例如。我有 2 个列表项,所以我将有两个距离属性,每个列表项一个。在调用 updateLatestDistance 方法时,应该更新特定列表项中的距离值,尽管这会导致两个列表项都包含 2 个最新距离。

Database dbDev= FirebaseDatabase.getInstance().getReference("Device");
dbDev.addValueEventListener(new ValueEventListener() {

    //In the onstart method
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) { //Read the value
            //Clear and regenerate the list so that no item is multipled.
            devices.clear();
            //Loop
            for(DataSnapshot deviceSnapshot : dataSnapshot.getChildren()){

                Device device = deviceSnapshot.getValue(Device.class);
                //Add the fetched data into the local list.
                devices.add(device);

                String checkId = deviceSnapshot.getKey();

                for(int i =0; i<devices.size(); i++){
                    //Grab the latest safety_zone's latitude for later usage.
                    DatabaseReference dbSafe_La = FirebaseDatabase.getInstance().getReference("Device/" +checkId+ "/SafetyZone/s_latitude");
                    dbSafe_La.addListenerForSingleValueEvent(new ValueEventListener() {
                        @Override
                        public void onDataChange(DataSnapshot dataSnapshot) {
                            //Check if safetyZone exists.
                            //If no, a 0.0 is passed.
                            if(dataSnapshot.exists()){
                                la = dataSnapshot.getValue(double.class);
                            }
                        }

                        @Override
                        public void onCancelled(DatabaseError databaseError) {
                        }
                    });
                    //Grab the latest safety_zone's longtitude for later usage.
                    DatabaseReference dbSafe_Lo = FirebaseDatabase.getInstance().getReference("Device/" +checkId+ "/SafetyZone/s_longitude");
                    dbSafe_Lo.addListenerForSingleValueEvent(new ValueEventListener() {
                        @Override
                        public void onDataChange(DataSnapshot dataSnapshot) {
                            //Check if safetyZone exists.
                            //If no, a 0.0 is passed.
                            if(dataSnapshot.exists()){
                                lo = dataSnapshot.getValue(double.class);
                            }
                        }
                        @Override
                        public void onCancelled(DatabaseError databaseError) {

                        }
                    });

                }
                /////////////////////////////////////////////////////


                updateLatestDistance(checkId, la, lo);

                ///showUpdateDidalog(device.getDeviceId(), device.getNickname());
            }

            //Create a new adapter
            DeviceListAdapter a = new DeviceListAdapter(Activity_Main.this, devices);
            listViewDevices.setAdapter(a);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

这是根据要求从 Firebase 控制台截取的屏幕截图。

这里是要求的 updateLatestDistance 方法。

//Function - Update the distance
    private boolean updateLatestDistance(String deviceId, double safety_la, double safety_lo){

        //Compute the latest distance between device's current location & selected safetyzone location.
        //To provide real-time distance changing
        //Firebase - Push latest distance.
        DatabaseReference dbLatest_distance = FirebaseDatabase.getInstance().getReference("Device/" +deviceId+ "/distance");
        DatabaseReference dbLatest_extra = FirebaseDatabase.getInstance().getReference("Device/" +deviceId+ "/extra");

        //Check if safetyZone defined
        if(safety_la!=0.0){
            float[] new_d = new float[3];
            //Compute the distance AGAIN.*
            Location.distanceBetween( Double.parseDouble(latitude), Double.parseDouble(longtitude), safety_la, safety_lo, new_d);

            //Push the distance data to the Firebase AGAIN.*
            dbLatest_distance.setValue(new_d[0]+"m");

            //If distance < 50m, trigger the alarm on the device (Raspberrypi)
            //By Sending 'on' or 'off' to Firebase.
            if(new_d[0] < 50){
                dbLatest_extra.setValue("on");
            }else{
                dbLatest_extra.setValue("off");
            }
        }

        return true;
    }

【问题讨论】:

  • 如果可能的话,发布一些你的 firebase 控制台的屏幕截图
  • @RahulChandrabhan Firebase 已更新。
  • 添加更新最新距离方法的代码
  • @UmarHussain 嗨,我已经更新了方法的代码。

标签: java android firebase firebase-realtime-database


【解决方案1】:

首先,由于您使用的是 ValueEventListener,当您在呼叫中写入最新距离时,您将多次触发该事件,因此请考虑使用 ChildValueEvent 来实际响应各个设备的变化。

接下来您不需要在计算之前再次读取值,因为 ValueEvent 或 ChildEvent 是实时的,并且一旦数据更改,它们就会再次被触发。所以你不需要使用单值事件读取安全区的值。

目前你的updateLatestDistance(checkId, la, lo); 也不会得到正确的值,因为单值事件调用是异步的。

我的建议是:

  • 初始化设备的空数组列表,onCreate中的列表视图适配器
  • 使用支持通知数据更改的适配器,例如我们使用带有 Recycler View 的 Recycler Adapter
  • 在 firebase 数据库的设备节点上使用 ChildValueEvent
  • onChild 添加或删除;从列表中添加或删除项目。 (您可能需要覆盖 Device 类中的 equals 方法才能直接从数组列表中执行此操作)。
  • onChildChange 将在您更新 firebase 中的设备属性时为您提供事件。
  • 现在,由于您的设备列表将与数据库同步,您可以在本地检查安全区并设置开启或关闭的值。 (在 onAdd 和 onChange child 中调用 update latest distance。也不需要检查来自 db 的数据,它会出现在你的设备类中)

        ChildEventListener childEventListener = new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
            Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
    
            // A new device has been added, add it to the list
           Device device = deviceSnapshot.getValue(Device.class);
                //Add the fetched data into the local list.
           devices.add(device);
           // notify your adapter about data change
           updateLatestDistance(dataSnapshot.getKey(), device.la, device.lo);
        }
    
        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
            Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
    
            //get device from list using device id for example. set the updated to the item in device list. notify
            updateLatestDistance(dataSnapshot.getKey(), device.la, device.lo);
    
        }
    
        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {
            Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
    
            // remove device from the list, notify adapter.
        }
    
        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
            Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
    
        }
    
        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.w(TAG, "postComments:onCancelled", databaseError.toException());
    }};
    

【讨论】:

  • 您好 Umar,非常感谢您指出我的代码中的错误部分。虽然我想知道我是否使用了 childEventListener,但我应该在哪里添加代码 clear() 和 setAdapter()?它们不适合 onChildAdded。 ://
  • Yoj 不需要清除列表,只需在列表中添加和删除项目并通知您的适配器有关数据的更改。您的设备列表适配器正在扩展哪个适配器?
  • 酷!我有工作! childEvent 运行良好,再次感谢:D
猜你喜欢
  • 1970-01-01
  • 2018-03-14
  • 2018-10-07
  • 1970-01-01
  • 2015-12-17
  • 2016-09-17
  • 2016-09-23
  • 1970-01-01
  • 2011-07-17
相关资源
最近更新 更多