#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 все еще не получила значение).