Я пытаюсь проверить наличие записи в моей базе данных Firebase асинхронно с помощью интерфейса, но я не уверен, как реализовать это так же, как для пароля и электронной почты.
Пример:
if (TextUtils.isEmpty(password) || !isPasswordValid(password)) {
mPasswordView.setError(getString(R.string.error_invalid_password));
focusView = mPasswordView;
cancel = true;
}
private boolean isPasswordValid(String password) {
// Add logic to check for a valid password (minimum 8 characters)
String confirmPassword = mConfirmPasswordView.getText().toString();
return (confirmPassword.equals(password)) && (password.length() > 7) && (password != "12345678") && (password != "password");
}
Я пытаюсь создать аналогичный метод с именем пользователя, который проверяет введенное имя пользователя в Firebase и затем возвращает true, если данные найдены. Я создал метод (fetchUsername) для проверки имени в Firebase в фоновом потоке, но не могу понять, как правильно передать результат обратно в последний метод и вернуть логическое значение. Я считаю, что делаю глупую синтаксическую ошибку, но не вижу ее. Вот что у меня есть:
private boolean isUsernameDuplicate(final String username) {
boolean userIsOnFirebase ( boolean isOnFirebase){ ///<----line that won't take, wants semicolon after variable
if (isOnFirebase) {
return true;
} else {
return false;
}
}
fetchUsername(username, new FirebaseSuccessListener() {
@Override
public void onDataFound(boolean isDataFetched) {
if (isDataFetched) {
userIsOnFirebase(true);
} else {
userIsOnFirebase(false);
}
}
});
return userIsOnFirebase;
}
private void fetchUsername(final String username, final FirebaseSuccessListener dataFetched) {
//checks database for username
mReference = FirebaseDatabase.getInstance().getReference().child("users").child("username");
mReference.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
dataFetched.onDataFound(true);
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
public interface FirebaseSuccessListener {
void onDataFound(boolean isDataFetched);
}
Обновлено: вот мое решение:
//member Variables
String checkedUsername;
private void attemptRegistration() {
// Reset errors displayed in the form.
mEmailView.setError(null);
mPasswordView.setError(null);
checkedUsername=null;
// Store values at the time of the login attempt.
String email = mEmailView.getText().toString();
String password = mPasswordView.getText().toString();
String username = mUsernameView.getText().toString();
boolean cancel = false;
View focusView = null;
if (TextUtils.isEmpty(username)) {
mUsernameView.setError(getString(R.string.error_field_required));
focusView = mUsernameView;
cancel = true;
}
if (!isUsernameValid(username)) {
mUsernameView.setError("Username is taken");
focusView = mUsernameView;
cancel = true;
}
private boolean isUsernameValid(String username) {
if (!duplicateUsername(username)) {
return true;
} else {
Toast.makeText(this, "Username is taken", Toast.LENGTH_LONG);
return false;
}
}
private boolean duplicateUsername(String username) {
if (fetchUsername(username) != null) {
return true;
}
return false;
}
private String fetchUsername(final String username) {
//checks database for username
mReference = FirebaseDatabase.getInstance().getReference().child("users");
mReference.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
User user = new User();
user = dataSnapshot.getValue(User.class);
if (user.getUsername() == username) {
checkedUsername = user.getUsername();
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
return checkedUsername;
}
Спасибо за ответ. Как мне получить данные из onDataChanged, чтобы сообщить другой части активности, что пользователь был найден? Инициализация переменной снаружи, если этот метод вынуждает меня сделать ее окончательной после того, как она будет использована там.
Нет, если variable создан как field. Вы можете обновить пользовательский интерфейс внутри onDataChange независимо от того, что вам нужно обновить в пользовательском интерфейсе, например, представить найденного пользователя с его именем.
Извиняюсь за то, что был таким тупым, но я думаю, что неправильно вас понял. Вот скриншот моей попытки сделать то, что вы описали, и ошибки, которую я получаю, когда пытаюсь создать переменную как поле. imgur.com/a/4rb7WaG
Переменная Field - это переменная variable, объявленная внутри класса, а не внутри метода. Variable внутри метода - это локальная переменная. У вас будет что-то вроде этого: public class YourClassName { private String fetchedUsername } Вы можете посмотреть здесь: stackoverflow.com/questions/10115588/…
Также этот метод не будет работать должным образом, я имею в виду, что вы не получите ожидаемого результата, return fetchedusername вернет null или начальное значение, если оно установлено.




Вот объяснение. Прежде всего, переменная field - это variable, созданный внутри class, к которой могут получить доступ все члены этого class. С другой стороны, variable, созданный внутри method, может быть доступен только членам этого метода, но не остальным членам class.
Firebase работает асинхронно (чтение и запись в базу данных) и реализует собственный callbacks, который вызывается в потоке пользовательского интерфейса. Например, один из этих обратных вызовов (в зависимости от сценария), который вы можете реализовать, это: onSuccessListener, addOnFailureListener, onCompleteListener, onDataChange. Этот callbacks дает вам информацию из Firebase (в данном случае из базы данных), либо запись была успешной, либо чтение было успешным, и у вас есть данные, готовые для использования в приложении, или что-то пошло не так. Внутри этих callbacks вы можете легко обновить свой пользовательский интерфейс.
Что вы делаете сейчас, так это создаете interface, который будет запускаться при срабатывании этого callbacks, и это один ненужный шаг, так как вы можете легко обновить пользовательский интерфейс внутри callback напрямую.
Кроме того, создаваемый вами метод, в котором вы хотите вернуть имя пользователя, не будет работать должным образом. Почему? Поскольку часть кода return fetchedusername выполняется до того, как результат будет возвращен из базы данных. Как вы уже знаете, Fireabse работает асинхронно и ему необходимо получать данные через Интернет, а тем временем return fetchedusername уже выполняется. Вот почему у вас есть методы callback.
Надеюсь, это кое-что прояснит.
Я считаю, что смог наконец собрать все воедино. Спасибо за вашу помощь и терпение. Смотрите мое решение в редакции.
Связь с Firebase с использованием его методов уже выполняется асинхронно. В зависимости от вашего запроса:
onCompleteListenerилиonSuccessListener,onDataChangeи т. д. - это обратные вызовы, которые выполняются в потоке пользовательского интерфейса, получая результаты из Firebase, поэтому вы можете обновить свой пользовательский интерфейс внутри этих обратных вызовов. Вам не нужно усложнять задачу с созданием собственногоinterfaces