Firebase извлекает данные нулевым внешним методом

#android #firebase #firebase-realtime-database #mpandroidchart #android-graphview

#Android #firebase #firebase-база данных в реальном времени

Вопрос:

Я поместил приведенный ниже метод внутри onCreate() , при запуске приложения он запустит этот метод. Но когда я пытаюсь выйти mName за ValueEventListener() пределы null , он возвращается, и приложение разбивается.

Кто-нибудь знает, почему возникает эта проблема?

  ValueEventListener postListener = new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            UserDetails info = dataSnapshot.getValue(UserDetails.class);
            Log.d(TAG, String.valueOf(dataSnapshot));

            mName = info.getName();
            **Log.d(TAG, mName); // HERE GET THE NAME**

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.w(TAG, "getUser:onCancelled", databaseError.toException());
        }
    };
    mDatabase.child("Admin")
            .child("Info")
            .child(uid)
            .addValueEventListener(postListener);

    **Log.d(TAG, mName); // HERE GET NULL**
  

Ответ №1:

Как уже говорили другие: все данные из базы данных Firebase считываются асинхронно. Проще всего убедиться в этом, добавив в свой код еще несколько инструкций log:

 Log.d(TAG, "Before attaching listener");
mDatabase.child("Admin")
        .child("Info")
        .child(uid)
        .addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        Log.d(TAG, "In listener's onDataChange");
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w(TAG, "getUser:onCancelled", databaseError.toException());
    }
});
Log.d(TAG, "After attaching listener");
  

В отличие от того, что вы можете ожидать, результатом этого является:

Перед подключением прослушивателя

После подключения прослушивателя

onDataChange внутреннего слушателя

Способ справиться с асинхронным поведением — это переосмыслить вашу проблему.

Прямо сейчас ваш код написан: сначала мы загружаем данные, затем регистрируем их.

Если вы переформулируете проблему следующим образом: «всякий раз, когда данные загружаются, мы регистрируем их», вы получите код, подобный этому:

 mDatabase.child("Admin")
        .child("Info")
        .child(uid)
        .addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        UserDetails info = dataSnapshot.getValue(UserDetails.class);
        Log.d(TAG, String.valueOf(dataSnapshot));

        mName = info.getName();
        Log.d(TAG, mName);

    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w(TAG, "getUser:onCancelled", databaseError.toException());
    }
});
  

Таким образом, весь код, которому нужны данные, должен находиться внутри onDataChange() . В качестве альтернативы вы можете создать свой собственный метод обратного вызова и вызвать его из onDataChange() . Но логика всегда одна и та же: код, которому нужны данные toe, запускается из, onDataChange() когда данные доступны.

Комментарии:

1. Отличное объяснение, большое вам спасибо. Но возникает другой вопрос, как мне передать данные другому действию на месте. Я пытался сохранить данные, используя sqlite внутри метода onDataChange. Но чтобы получить их, я должен закрыть и снова открыть приложение.

Ответ №2:

Это потому, что Firebase все еще не извлекла данные в то время, когда вы это делаете:

 Log.d(TAG, mName);
  

mName в настоящее время равно нулю, поскольку эта строка была выполнена до того, как Firebase получила данные.

Чтобы решить эту проблему, вы должны Log.d(TAG, mName) внутри onDataChange метода. В противном случае это будет null , поскольку вы еще не установили значение (поскольку Firebase все еще не получила значение).