Пользовательский интерфейс firebase - пользовательский snapshotparser пропускается компилятором

Итак, я использую пользовательский интерфейс Firebase для получения данных из базы данных. Это выглядит так: Database

Я хочу перебирать «сообщения», чтобы получить каждого ребенка, и показать его как сообщение в моем приложении. Вот так выглядит мой класс UserMessage:

public class UserMessage {

private String mUserLogin;
private String mUserMessage;
private String mUID;

UserMessage(String userLogin, String userMessage, String uid) {
    mUserLogin = userLogin;
    mUserMessage = userMessage;
    mUID = uid;
}

public String getmUserLogin() {
    return mUserLogin;
}

public void setmUserLogin(String mUserLogin) {
    this.mUserLogin = mUserLogin;
}

public String getmUserMessage() {
    return mUserMessage;
}

public String getmUID() {
    return mUID;
}

public void setmUID(String mUID) {
    this.mUID = mUID;
}


public void setmUserMessage(String mUserMessage) {
    this.mUserMessage = mUserMessage;
}

}

И я хочу получить это через FirebaseRecyclerOptions:

FirebaseRecyclerOptions<UserMessage> options =
            new FirebaseRecyclerOptions.Builder<UserMessage>()
            .setQuery(firebaseDatabaseModel.getQuery(), new SnapshotParser<UserMessage>() {
                @NonNull
                @Override
                public UserMessage parseSnapshot(@NonNull DataSnapshot snapshot) {
                    Log.d("snapshot length", String.valueOf(snapshot.getChildrenCount()));
                    return snapshot.getValue(UserMessage.class);
                }
            })
            .build();

А вот как выглядит мой метод firebaseDatabaseModel.getQuery ():

 public Query getQuery() {
DatabaseReference messageReference =    database.child("messages");
    return messageReference.limitToLast(50);
}

И вот как я хочу установить данные в своем FirebaseRecyclerAdapter

class ChatMessagesAdapter extends FirebaseRecyclerAdapter<UserMessage, ChatMessagesAdapter.ChatHolder> {
private UserMessage[] userMessages;

/**
 * Initialize a {@link RecyclerView.Adapter} that listens to a Firebase query. See
 * {@link FirebaseRecyclerOptions} for configuration options.
 *
 * @param options
 */
public ChatMessagesAdapter(@NonNull FirebaseRecyclerOptions<UserMessage> options) {
    super(options);
    userMessages = (UserMessage[]) options.getSnapshots().toArray();
       }

@Override
protected void onBindViewHolder(@NonNull ChatHolder holder, int position, @NonNull UserMessage model) {

    holder.message.setText(userMessages[position].getmUserMessage());
    holder.user.setText(userMessages[position].getmUserLogin());

}

@NonNull
@Override
public ChatHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_message, parent, false);
    return new ChatHolder(view);
}

static class ChatHolder extends RecyclerView.ViewHolder {

    @BindView(R.id.user_message)
    TextView message;
    @BindView(R.id.user_login)
    TextView user;

    private ChatHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(itemView);

    }
}

}

Дело в том, что независимо от того, как я пытаюсь отправить параметры (сообщения пользователя) через массив в FirebaseRecyclerAdapter, счетчик всегда равен нулю. Вероятно, проблема кроется в пользовательском парсере (я должен правильно его составить), но мой отладчик просто пропускает эту часть кода:

 public UserMessage parseSnapshot(@NonNull DataSnapshot snapshot) {
                Log.d("snapshot length", String.valueOf(snapshot.getChildrenCount()));
                return snapshot.getValue(UserMessage.class);
            }

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

// Редактировать 1: Из-за предложений @Alex Malmo я изменил ключи базы данных на: enter image description here

И UserMessage.class для:

public class UserMessage {
private String userLogin, userMessage, uid;

public UserMessage() {}

public UserMessage(String userLogin, String userMessage, String uid) {
    this.userLogin = userLogin;
    this.userMessage = userMessage;
    this.uid = uid;
}

public String getUserLogin() { return userLogin; }
public String getUserMessage() { return userMessage; }
public String getUid() { return uid; }

}

Похоже, что эта штука все еще находится в создании FirebaseRecyclerOptions. Я пробовал эти два метода:

FirebaseRecyclerOptions<UserMessage> options = new FirebaseRecyclerOptions.Builder<UserMessage>()
            .setQuery(query,
                    UserMessage.class)
            .build();

а также

    FirebaseRecyclerOptions<UserMessage> options = new FirebaseRecyclerOptions.Builder<UserMessage>()
            .setQuery(query,
                    new SnapshotParser<UserMessage>() {
                        @NonNull
                        @Override
                        public UserMessage parseSnapshot(@NonNull DataSnapshot snapshot) {
                            return snapshot.getValue(UserMessage.class);
                        }
                    })
            .build();

В обоих случаях - второй аргумент в методе setQuery (часть синтаксического анализа), похоже, игнорируется (компилятор просто пропускает эту часть - он получает правильный запрос и переходит прямо к .build ()), что, похоже, представляет собой целую проблему с пустыми данными в адаптер.

Во-первых, вам не хватает пустого конструктора в классе модели: public UserMessage() { }, который необходим для адаптера пользовательского интерфейса Firebase.

Yupi 13.09.2018 21:57

@Yupi, спасибо за предложение. Я уже это сделал. Но тогда это все еще не помогает в решении всей проблемы парсера (по крайней мере, я так думаю?). Я основываю свои знания на github.com/firebase/FirebaseUI-Android/blob/master/database/‌… и некоторых других проблемах с этим на Stack, но я просто не могу найти правильного решения для своей проблемы.

Damian Ziółkowski 13.09.2018 22:06

У вашего DatabaseRefrence правильный путь к узлу messages?

Yupi 13.09.2018 22:07

Я отправляю свои сообщения по той же ссылке (например, messageReference.push (). SetValue (userMessage);), и все работает нормально.

Damian Ziółkowski 13.09.2018 22:11

Возможно, вам не хватает this внутри: ButterKnife.bind(this, itemView); также класс должен быть public

Yupi 13.09.2018 22:23

@Yupi Я думаю, что это не так, по крайней мере, сейчас. Проблема в том, что «параметры» пусты в адаптере, поэтому проблема, вероятно, заключается в создании / передаче этих FirebaseRecyclerOptions. Биндеру сейчас даже нечего связывать.

Damian Ziółkowski 13.09.2018 22:42
0
6
867
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Проблема в вашем коде в том, что вы используете неправильные геттеры для своих полей. В полях класса вашей модели, которые начинаются со строчной буквы. Когда вы используете поле с именем mUserLogin, Firebase ищет получатель с именем getMUserLogin(), а не getmUserLogin(). Видите заглавную букву M и строчную букву m? Вероятно, это наиболее вероятная причина, по которой вы ничего не получаете. Ваш класс модели должен выглядеть правильно:

public class UserMessage {
    private String userLogin, userMessage, uid;

    public UserMessage() {}

    public UserMessage(String userLogin, String userMessage, String uid) {
        this.userLogin = userLogin;
        this.userMessage = userMessage;
        this.uid = uid;
    }

    public String getUserLogin() { return userLogin; }
    public String getUserMessage() { return userMessage; }
    public String getUid() { return uid; }
}

Чтобы иметь правильные данные в вашей базе данных, просто Удалить старые данные и Добавить свежие. Теперь ваш код должен работать.

Вы также можете взглянуть на Соглашения об именах Java.

Спасибо за предложения @Alex Mamo. Я это проверил. К сожалению, все же дело в том, что при создании FirebaseRecyclerOptions он просто пропускает часть синтаксического анализа (он получает запрос, затем он переходит прямо к части .build, пропуская UserMessage.class или создавая новый SnapshotParser), как будто что-то не так с запросом .

Damian Ziółkowski 14.09.2018 12:16

Вы тоже просто пробовали использовать этот FirestoreRecyclerOptions<UserMessage> options = new FirestoreRecyclerOptions.Builder<UserMessage>().setQuery(fir‌​ebaseDatabaseModel.g‌​etQuery(), UserMessage.class).build();?

Alex Mamo 14.09.2018 12:32

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

Alex Mamo 14.09.2018 12:33

Вы тоже начали прислушиваться к изменениям, как в моем ответе из этого Почта?

Alex Mamo 14.09.2018 12:59
Ответ принят как подходящий

Хорошо, я наконец решил это. Проблема заключалась в том, что я совершенно неправильно понял функции FirebaseRecyclerOptions. Я был полностью уверен, что он передает данные внутри него, и все дело в том, что я пытался получить эти данные, не позволяя всему методу выполнять свою работу.

Поэтому я изменил конструкцию адаптера с:

 class ChatMessagesAdapter extends FirebaseRecyclerAdapter<UserMessage, ChatMessagesAdapter.ChatHolder> {
private UserMessage[] userMessages;

/**
 * Initialize a {@link RecyclerView.Adapter} that listens to a Firebase query. See
 * {@link FirebaseRecyclerOptions} for configuration options.
 *
 * @param options
 */
public ChatMessagesAdapter(@NonNull FirebaseRecyclerOptions<UserMessage> options) {
    super(options);
    userMessages = (UserMessage[]) options.getSnapshots().toArray();
       }

@Override
protected void onBindViewHolder(@NonNull ChatHolder holder, int position, @NonNull UserMessage model) {

    holder.message.setText(userMessages[position].getmUserMessage());
    holder.user.setText(userMessages[position].getmUserLogin());

}

@NonNull
@Override
public ChatHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_message, parent, false);
    return new ChatHolder(view);
}

static class ChatHolder extends RecyclerView.ViewHolder {

    @BindView(R.id.user_message)
    TextView message;
    @BindView(R.id.user_login)
    TextView user;

    private ChatHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(itemView);

    }
}

К:

class ChatMessagesAdapter extends FirebaseRecyclerAdapter<UserMessage, ChatMessagesAdapter.ChatHolder> {
    private ArrayList<UserMessage> messagesList = new ArrayList<>();

    /**
     * Initialize a {@link RecyclerView.Adapter} that listens to a Firebase query. See
     * {@link FirebaseRecyclerOptions} for configuration options.
     *
     * @param options
     */
    ChatMessagesAdapter(@NonNull FirebaseRecyclerOptions<UserMessage> options) {
        super(options);           }

    @Override
    protected void onBindViewHolder(@NonNull ChatHolder holder, int position, @NonNull UserMessage model) {
        messagesList.add(model);
        holder.message.setText(messagesList.get(position).getUserMessage());
        holder.user.setText(messagesList.get(position).getUserLogin());

    }

    @NonNull
    @Override
    public ChatHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_message, parent, false);
        return new ChatHolder(this,view);
    }


    static class ChatHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.user_message)
        TextView message;
        @BindView(R.id.user_login)
        TextView user;

        private ChatHolder(ChatMessagesAdapter chatMessagesAdapter, View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);

        }
    }

}

И работает отлично. Я основал это на этом примере: https://www.programcreek.com/java-api-examples/?code=panzerama/Dispatch/Dispatch-master/app/src/main/java/com/indexyear/jd/dispatch/activities/DispatchTeamActivity.java

Так что, если у вас возникнут проблемы со всем FirebaseUI, на мой взгляд, приведенный выше пример является подходящим.

Спасибо @Alex Malmo и @Yupi за предложения!

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