Обратный вызов дочернего прослушивателя Firebase Возвращает одно значение и ноль для второго значения. - PullRequest
0 голосов
/ 09 октября 2018

Я сталкиваюсь с очень странными результатами при работе базы данных Firebase в реальном времени для Android.Основная проблема:

  1. Когда я пытаюсь добавить дочерний элемент с двумя полями, метод onChildAdded возвращает вставленное значение для первого ключа и ноль для второго и не вызывается для второго значения вновь вставленногоchild.
  2. Когда я пытаюсь сделать то же самое с помощью valueEventListener, метод onDataChange вызывается дважды при создании нового дочернего элемента.В первом обратном вызове значение одного поля в возвращаемом и втором значении равно нулю, а во втором обратном вызове возвращаются оба обновленных значения.

У меня есть эта структура в моей базе данных firebase.

{
  "users" : {
    "-LOOlXqtc0XK3ZXLKFc6" : {
      "Age" : 50,
      "Name" : "Ali"
    },
    "-LOPIfgGQMhyMkRMcpTb" : {
      "Age" : 80,
      "Name" : "New Name"
    }
  }
}

И это мой код MainActivity:

mDatabase = FirebaseDatabase.getInstance();
mRef = mDatabase.getReference("users");

Этот код выполняется на данных вставкиНажатие кнопки.

private void runCode(View view){
        String name = mInputText.getText().toString();
        int age= Integer.parseInt(mInputNum.getText().toString());

        String key = mRef.push().getKey();
        mRef.child(key).child("Name").setValue(name);
        mRef.child(key).child("Age").setValue(age);
}

И это метод чтения данных по нажатию кнопки с использованием valueEventListener.

private void readData(View view) {
        //read data here 
        //this read data method has value listener not child listener
        mRef.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                Person data=  dataSnapshot.getValue(Person.class);
                Map<String,Object> data1= (Map<String, Object>) dataSnapshot.getValue();

                Log.d(TAG, "onChildAdded: Name: "+data1.get("Name"));
                Log.d(TAG, "onChildAdded: Age: "+data1.get("Age"));
                Log.d(TAG, "This is Person: "+data);
            }
            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
            }
        });
}

Вывод logcat такой: Это когда я нажимаю на метод Чтение данных дляв первый раз.

D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: This is Person: Person{Name='Ali', Age=50}

И это вывод logcat, когда я вставляю нового потомка с именем = "Новое имя" и возрастом = 80.

D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: This is Person: Person{Name='Ali', Age=50}
D/MyTag: onChildAdded: Name: New Name
D/MyTag: onChildAdded: Age: null
D/MyTag: This is Person: Person{Name='New Name', Age=0}
D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: This is Person: Person{Name='Ali', Age=50}
D/MyTag: onChildAdded: Name: New Name
D/MyTag: onChildAdded: Age: 80
D/MyTag: This is Person: Person{Name='New Name', Age=80}

Метод обратного вызова выполняется отдельнодля каждого поля он возвращает по одному полю за раз, но это имеет смысл, что setField вызывается дважды, поэтому может быть, поэтому оно вызывается.Но с дочерним слушателем дело обстоит еще хуже.

Вот метод Read Code с реализацией childListener.

private void readData(View view) {
        //read data here
        mRef.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
                Map<String,Object> data= (Map<String, Object>) dataSnapshot.getValue();
                Person p=dataSnapshot.getValue(Person.class);

                Log.d(TAG, "onChildAdded: Name: "+data.get("Name"));
                Log.d(TAG, "onChildAdded: Age: "+data.get("Age"));

                Log.d(TAG, "onChildAdded: Person is: "+p);
            }
            @Override
            public void onChildChanged(@NonNull DataSnapshot       dataSnapshot, @Nullable String s) {
            }
            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
            }
            @Override
            public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
            }
            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
}

Вот вывод logcat, когда я впервые нажимаю кнопку чтения данных:

D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: onChildAdded: Person is: Person{Name='Ali', Age=50}
D/MyTag: onChildAdded: Name: New Name
D/MyTag: onChildAdded: Age: 80
D/MyTag: onChildAdded: Person is: Person{Name='New Name', Age=80}

И это вывод с добавлением нового ребенка с Name = "Usman" и age = 50

D/MyTag: onChildAdded: Name: Usman
D/MyTag: onChildAdded: Age: null
D/MyTag: onChildAdded: Person is: Person{Name='Usman', Age=0}

Только это происходит в обратном вызове.Возраст не возвращается, но значение правильно хранится в базе данных.

Пожалуйста, помогите.У меня подключен только один слушатель, и я всегда запускаю приложение после остановки запущенного процесса.Спасибо.

1 Ответ

0 голосов
/ 09 октября 2018

Когда вы запускаете этот код:

mRef.child(key).child("Name").setValue(name);
mRef.child(key).child("Age").setValue(age);

Каждый вызов setValue отправляется в базу данных Firebase отдельно.Итак, вы выполняете две независимые операции записи в базу данных.И каждая операция записи может быть отправлена ​​слушателям.

Чтобы сделать их одной операцией записи, объедините два свойства в один вызов setValue():

Map<String, Object> values = new HashMap<String, Object>();
map.put("Name", name);
map.put("Age", age);
mRef.child(key).setValue(values);

Это выполнит одну запись в базу данных с тем же конечным результатом.Но он вызовет слушателя только один раз.

Обновление

Если мы оглянемся на ваш исходный код:

mRef.child(key).child("Name").setValue(name);
mRef.child(key).child("Age").setValue(age);

Первый вызов setValue вызывает $key кбыть созданным, в то время как второй вызов просто обновляет узел Age под ним.При использовании дочернего прослушивателя на mRef это означает, что первый вызов setValue() вызывает onChildAdded, а второй вызов onChildChanged().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...