Я неправильно реализую ValueEventListener, используя интерфейс

Я пытаюсь проверить наличие записи в моей базе данных 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;

    }

Связь с Firebase с использованием его методов уже выполняется асинхронно. В зависимости от вашего запроса: onCompleteListener или onSuccessListener, onDataChange и т. д. - это обратные вызовы, которые выполняются в потоке пользовательского интерфейса, получая результаты из Firebase, поэтому вы можете обновить свой пользовательский интерфейс внутри этих обратных вызовов. Вам не нужно усложнять задачу с созданием собственного interfaces

Yupi 28.09.2018 01:18

Спасибо за ответ. Как мне получить данные из onDataChanged, чтобы сообщить другой части активности, что пользователь был найден? Инициализация переменной снаружи, если этот метод вынуждает меня сделать ее окончательной после того, как она будет использована там.

andrewedgar 28.09.2018 16:35

Нет, если variable создан как field. Вы можете обновить пользовательский интерфейс внутри onDataChange независимо от того, что вам нужно обновить в пользовательском интерфейсе, например, представить найденного пользователя с его именем.

Yupi 28.09.2018 20:27

Извиняюсь за то, что был таким тупым, но я думаю, что неправильно вас понял. Вот скриншот моей попытки сделать то, что вы описали, и ошибки, которую я получаю, когда пытаюсь создать переменную как поле. imgur.com/a/4rb7WaG

andrewedgar 28.09.2018 23:54

Переменная Field - это переменная variable, объявленная внутри класса, а не внутри метода. Variable внутри метода - это локальная переменная. У вас будет что-то вроде этого: public class YourClassName { private String fetchedUsername } Вы можете посмотреть здесь: stackoverflow.com/questions/10115588/…

Yupi 29.09.2018 00:29

Также этот метод не будет работать должным образом, я имею в виду, что вы не получите ожидаемого результата, return fetchedusername вернет null или начальное значение, если оно установлено.

Yupi 29.09.2018 00:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
6
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот объяснение. Прежде всего, переменная 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.

Надеюсь, это кое-что прояснит.

Я считаю, что смог наконец собрать все воедино. Спасибо за вашу помощь и терпение. Смотрите мое решение в редакции.

andrewedgar 29.09.2018 01:06

Другие вопросы по теме