#android #firebase-realtime-database #firebase-authentication
# #Android #firebase-база данных в реальном времени #firebase-аутентификация
Вопрос:
Я работаю над некоторым приложением для Android, в котором два типа пользователей могут входить в систему, а база данных отображает их информацию. Допустим, одним типом пользователя будет клиент («Пользователи»), а другим — ресторан («Рестораны»). Проблема начинается, когда я пытаюсь прочитать данные пользователя из базы данных. Приложение работает нормально и отображает информацию о пользователе, когда у меня есть только один тип пользователя (дочерние «Пользователи»), но когда я добавляю еще один (дочерние «Рестораны»), кажется, что приложение не знает, от какого дочернего пользователя выполнен вход в систему? Надеюсь, это имеет смысл 🙂
// JSON
{
"Restaurants" : {
"4kASMGuVlxgk8HiDsxEt7IcSo4y2" : {
"restaurantEmail" : "res1@gmail.com",
"restaurantName" : "res1",
"restaurantPhone" : "123456"
},
"6FwZR8rYxyVKm8FC8v0jV4ZwgVs2" : {
"restaurantEmail" : "1604@gmail.com",
"restaurantName" : "restaurant1604",
"restaurantPhone" : "123456"
},
"vERcsGqBA0VNDjXfNvrseA29UGc2" : {
"restaurantEmail" : "restaurant3@gmail.com",
"restaurantName" : "restaurant3",
"restaurantPhone" : "123456"
}
},
"Users" : {
"3BCqSyocaScBiviSUf2QAXo5Fdu1" : {
"phoneNumber" : "123456",
"userEmail" : "test3@gmail.com",
"userName" : "test3"
},
"wzz9NBQt2YfFikMHTaMIcdRyCRI2" : {
"phoneNumber" : "123456",
"userEmail" : "test5@gmail.com",
"userName" : "test5"
}
}
}
// JAVA
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WelcomeActivity = new Intent(this,com.example.danie.dine.Activities.WelcomeActivity.class);
BookingManagementActivity = new Intent(this,com.example.danie.dine.Activities.BookingManagementActivity.class);
setContentView(R.layout.activity_home);
mAuth = FirebaseAuth.getInstance();
FirebaseUser currentUser = mAuth.getCurrentUser();
userID = currentUser.getUid();
mDatabase = FirebaseDatabase.getInstance();
mRef = mDatabase.getReference("Users");
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
showMessage("Successfully signed in with: " user.getEmail());
} else {
// User is signed out
showMessage("Successfully signed out.");
}
// ...
}
};
// добавление недостающей части кода
mRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
showInfo(dataSnapshot);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
// JAVA для попытки чтения из базы данных — не работает
private void showInfo(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()){
UserInformation uInfo = new UserInformation();
uInfo.setUserName(ds.child(userID).getValue(UserInformation.class).getUserName()); //get username
uInfo.setUserEmail(ds.child(userID).getValue(UserInformation.class).getUserEmail()); //get user email
uInfo.setPhoneNumber(ds.child(userID).getValue(UserInformation.class).getPhoneNumber()); //get user phone number
//display user details
lblUserName.setText(uInfo.getUserName()); //error points here
lblUserEmail.setText(uInfo.getUserEmail());
lblUserPhone.setText(uInfo.getPhoneNumber());
}
}
//missing part of code #2
@Override
public void onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
@Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}
//JAVA userInfo Object
public class UserInformation {
private String userName;
private String phoneNumber;
private String userEmail;
public UserInformation(){
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public UserInformation(String userName, String phoneNumber, String userEmail) {
this.userName = userName;
this.phoneNumber = phoneNumber;
this.userEmail = userEmail;
}
}
До сих пор то, что я пробовал, если у меня есть только один дочерний «Пользователь», приложение считывает и отображает из базы данных без каких-либо проблем, как только я добавляю дочерние «Рестораны», все идет наперекосяк… Я предполагаю, что мне нужно как-то указать код для чтения дочерних «пользователей» только, поскольку я пытаюсь отображать только информацию о пользователях, а не «Рестораны»?
// сообщение об ошибке
2019-04-17 11:44:33.116 11557-11557/com.example.danie.dine E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.danie.dine, PID: 11557
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.danie.dine.Model.UserInformation.getUserName()' on a null object reference
at com.example.danie.dine.Activities.HomeActivity.showInfo(HomeActivity.java:172)
at com.example.danie.dine.Activities.HomeActivity.access$100(HomeActivity.java:30)
at com.example.danie.dine.Activities.HomeActivity$2.onDataChange(HomeActivity.java:93)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@16.0.5:75)
at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@16.0.5:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@16.0.5:55)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
// предлагаемое исправление
mRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
UserInformation userDetails = dataSnapshot.getValue(UserInformation.class);
userDetails.getUserName();
userDetails.getPhoneNumber();
userDetails.getUserEmail();
userDetails.setUserName(dataSnapshot.child(userID).getValue(UserInformation.class).getUserName()); //get username
userDetails.setUserEmail(dataSnapshot.child(userID).getValue(UserInformation.class).getUserEmail()); //get user email
userDetails.setPhoneNumber(dataSnapshot.child(userID).getValue(UserInformation.class).getPhoneNumber()); //get user phone number
lblUserName.setText(userDetails.getUserName());
lblUserEmail.setText(userDetails.getUserEmail());
lblUserPhone.setText(userDetails.getPhoneNumber());
Комментарии:
1. Пожалуйста, добавьте весь код, который вы используете для получения данных из базы данных/
2. Устанавливаете ли вы ссылку на базу данных перед вызовом запроса или прослушивателя? Все, что я вижу из вашего опубликованного кода, это mRef = mDatabase.getReference(); что, если оставить так, вызовет проблему.
3. Привет @Alex Mamo, прошу прощения, добавлена недостающая часть кода. Спасибо!
4. @DanielCzajka Разве ваш
mRef
не должен быть определен как:mDatabase.getReference().child("Users")
? Пожалуйста, ответьте с помощью @AlexMamo5. Привет, Мена, я предполагаю, что это также может быть источником моей проблемы. Я только что попытался добавить mRef=mDatabase.getReference().child(«Пользователи»); но по-прежнему не воспроизводится… @AlexMamo, только что попробовал, то же самое… это дает мне java.lang. Исключение NullPointerException, поскольку оно не может считывать информацию из базы данных…
Ответ №1:
Короче говоря
Вам нужно создать два метода: один getUser()
и другой getRestaurant()
, потому что база данных, как вы ее представили, имеет два корневых узла: пользователи и рестораны.
Если, с другой стороны, вы сохранили всех пользователей (то есть пользователей и рестораны) в одном списке с дополнительным атрибутом типа ( type:0
для User и type:1
для Restaurant, или type:user
и type:restaurant
), одной ссылки на базу данных будет достаточно. Все, что вам нужно сделать, это создать базовую модель, которую должны расширять UserModel и RestaurantModel, и после прочтения type
вы создадите User или Restaurant.
Я надеюсь, что это отвечает на ваш вопрос.
Комментарии:
1. Привет @Variag, спасибо за ваш ответ. На данный момент я пытаюсь прочитать информацию только от дочерних пользователей (метод ShowInfo ()). даже если я делаю mRef = mDatabase.getReference().child(«Пользователи»); он по-прежнему не читает только из дочернего элемента «Users», и я не знаю почему…
2. @AlexMamo просто дважды проверил это, да, на это указывает строка ошибки кода. По сути, ни один из этих трех (GetUserName, getUserEmail, getUserPhone), похоже, не работает, я комментировал их один за другим и всегда сначала не комментировал, выдавал ошибку…
3. @DanielCzajka
dataSnapshot
перед отправкой вshowInfo()
метод не пусто? Добавляются ли значения к объектуuInfo
? Правильные ли значения?
Ответ №2:
Большое спасибо за все ваши советы, я сослался на документацию firebase и повторил все функции чтения из базы данных с нуля. Похоже, что мой метод userInfo() не работал, я избавился от него и создал новый (код добавлен в комментарии //proposal fix. Я надеюсь, что кто-то найдет это полезным. извлеченный урок 🙂