firebase / FirebaseUI-Android

Optimized UI components for Firebase
https://firebaseopensource.com/projects/firebase/firebaseui-android/
Apache License 2.0
4.63k stars 1.83k forks source link

FirestoreRecyclerAdapter doesn't work inside Fragment #1593

Closed sbotev5 closed 5 years ago

sbotev5 commented 5 years ago

I want to use a RecyclerView inside a Fragment but it doesn't seem to be working. The query works (it gives the documents) and I have used almost the same code in an Activity - not sure why this doesn't work.

I want to display messages associated with a "tenancy" in my Recycler view:

Message.java getters and setters omitted. `public class Message { private String content; @ServerTimestamp private Timestamp timestamp; private String from;

public Message(String content, Timestamp timestamp, String from) {
    this.content = content;
    this.timestamp = timestamp;
    this.from = from;
}

public Message() {

}

` MessageAdapter.java

`public class MessageAdapter extends FirestoreRecyclerAdapter<Message, MessageAdapter.MessageHolder> {

/**
 * Create a new RecyclerView adapter that listens to a Firestore Query.  See {@link
 * FirestoreRecyclerOptions} for configuration options.
 *
 * @param options
 */

public MessageAdapter(@NonNull FirestoreRecyclerOptions<Message> options) {
    super(options);

}

@Override
protected void onBindViewHolder(@NonNull MessageHolder holder, int position, @NonNull Message model) {
    //holder.itemView.setBackgroundColor(Color.parseColor("#C5CAE9"));
    //If you want to alternate colours for some reason, use position and modulo operator.

    holder.fromText.setText(model.getFrom());
    holder.contentText.setText(model.getContent());
    holder.timestampText.setText(DateFormat.format("dd-MM-yyyy (HH:mm:ss)", model.getTimestamp().toDate()));

}

@NonNull
@Override
public MessageHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {

    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.message_row, viewGroup, false);

    return new MessageHolder(v);
}

class MessageHolder extends RecyclerView.ViewHolder {

    TextView fromText;
    TextView timestampText;
    TextView contentText;

    MessageHolder(@NonNull View itemView) {
        super(itemView);

        fromText = itemView.findViewById(R.id.fromText);
        timestampText = itemView.findViewById(R.id.timestampText);
        contentText = itemView.findViewById(R.id.contentText);

        //itemView.setBackground(ContextCompat.getDrawable(itemView.getContext(), R.color.secondary_text));

    }

}

}`

MessagesFragment.java

`public class MessagesFragment extends Fragment {

private FirebaseAuth mAuth = FirebaseAuth.getInstance();
private FirebaseFirestore db = FirebaseFirestore.getInstance();

private MessageAdapter myAdapter;
private FloatingActionButton sendMessage;
private EditText enterMessage;
private RecyclerView recyclerView;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_messages, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {

    fetchMessages(getActivity().getIntent().getStringExtra("tenancy_id"), view);

    sendMessage = view.findViewById(R.id.sendMessage);
    enterMessage = view.findViewById(R.id.enterMessage);

    sendMessage.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (enterMessage.getText().toString().isEmpty()) {

                enterMessage.setError("Please enter your message");

            } else {
                sendMessage(getActivity().getIntent().getStringExtra("tenancy_id"), getActivity().getIntent().getStringExtra("user_name"));
            }
        }
    });

}

private void sendMessage(String tenancyDocPath, String from) {

    //Timestamp value passed is null because this way FireStore will put a Server Timestamp value when being added.

    Message message = new Message(enterMessage.getText().toString(), null, from);

    db.document(tenancyDocPath).collection("messages").add(message).addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
        @Override
        public void onSuccess(DocumentReference documentReference) {
            enterMessage.setText("");
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {

        }
    });

}

private void fetchMessages(String tenancyDocPath, View view) {

    Query query = db.document(tenancyDocPath).collection("messages").orderBy("timestamp");

    FirestoreRecyclerOptions<Message> options = new FirestoreRecyclerOptions.Builder<Message>().setQuery(query, Message.class).build();

    myAdapter = new MessageAdapter(options);

    recyclerView = view.findViewById(R.id.messagesList);
    recyclerView.setHasFixedSize(true);

    recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

    recyclerView.setAdapter(myAdapter);

}

@Override
public void onStop() {
    super.onStop();
    myAdapter.startListening();
}

@Override
public void onStart() {
    super.onStart();
    myAdapter.stopListening();
}

}`

fragment_messages.xml

`<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/icons">

<android.support.v7.widget.RecyclerView
    android:id="@+id/messagesList"
    android:layout_height="448dp"
    android:layout_width="match_parent"
    android:layout_marginStart="6dp"
    android:layout_marginTop="6dp"
    android:layout_marginEnd="6dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<View
    android:id="@+id/divider"
    android:layout_width="395dp"
    android:layout_height="1dp"
    android:layout_marginStart="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="47dp"
    android:background="@color/secondary_text"
    app:layout_constraintBottom_toTopOf="@+id/enterMessage"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/sendMessage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="16dp"
    android:layout_marginTop="60dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="25dp"
    android:clickable="true"
    app:backgroundTint="@color/design_default_color_primary"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="1.0"
    app:layout_constraintStart_toEndOf="@+id/enterMessage"
    app:layout_constraintTop_toBottomOf="@+id/divider"
    app:srcCompat="@drawable/ic_send_white_24dp" />

<EditText
    android:id="@+id/enterMessage"
    android:layout_width="323dp"
    android:layout_height="87dp"
    android:layout_marginStart="7dp"
    android:layout_marginTop="14dp"
    android:layout_marginBottom="7dp"
    android:background="@drawable/border_blue"
    android:ems="10"
    android:gravity="top|left"
    android:hint="Say something nice :)"
    android:inputType="textMultiLine"
    android:textColor="@color/design_default_color_primary"
    android:textColorHint="@color/secondary_text"
    android:textSize="17sp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/newMessage" />

<TextView
    android:id="@+id/newMessage"
    android:layout_width="171dp"
    android:layout_height="24dp"
    android:layout_marginStart="7dp"
    android:layout_marginTop="12dp"
    android:layout_marginEnd="233dp"
    android:text="New message..."
    android:textColor="@color/design_default_color_primary"
    android:textSize="18sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/divider" />

</android.support.constraint.ConstraintLayout>`

message_row.xml

`<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content">

<TextView
    android:id="@+id/fromText"
    android:layout_width="150dp"
    android:layout_height="19dp"
    android:layout_marginStart="16dp"
    android:layout_marginTop="5dp"
    android:layout_marginEnd="107dp"
    android:text="TextView"
    android:textAlignment="viewStart"
    android:textColor="@color/primary_text"
    android:textStyle="bold"
    app:layout_constraintEnd_toStartOf="@+id/timestampText"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/timestampText"
    android:layout_width="122dp"
    android:layout_height="24dp"
    android:layout_marginTop="5dp"
    android:layout_marginEnd="16dp"
    android:text="TextView"
    android:textAlignment="textEnd"
    android:textColor="@color/secondary_text"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/contentText"
    android:layout_width="254dp"
    android:layout_height="117dp"
    android:layout_marginStart="16dp"
    android:layout_marginTop="20dp"
    android:layout_marginEnd="141dp"
    android:text="TextView"
    android:textAlignment="viewStart"
    android:textColor="@color/primary_text"
    android:textSize="16sp"
    android:textStyle="bold"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/fromText" />

</android.support.constraint.ConstraintLayout>`

Thanks in advance for any help.

Regards,

sbotev5

samtstern commented 5 years ago

What exactly doesn't work in a Fragment? Some screenshots or logs would be really helpful! As it stands there's a lot of code here so it's hard to know where to start.

On Sun, Mar 3, 2019, 10:28 AM sbotev5 notifications@github.com wrote:

Fragment logic transferred on an Activity class works fine. This is weird.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/firebase/FirebaseUI-Android/issues/1593#issuecomment-469049904, or mute the thread https://github.com/notifications/unsubscribe-auth/AIEw6nnleANWPmsR3nL_0_IdxeNVFjrfks5vTBROgaJpZM4bahcc .

sbotev5 commented 5 years ago

Apologies everyone.

The problem is in MessagesFragment.java

I call adapter.startListening in onStop and stopListening in onStart. Should be vice versa.

gptshubham595 commented 4 years ago

what was the problem ? did you solved it ? How?

shubhamnandanwar commented 3 years ago

I am having the same problem and my listeners are fine

ahmedbilal205 commented 2 years ago

I am having the same problem and my listeners are fine, Everything seems fine, I can run the same query and it runs fine but FirebaseUI's "onBindViewHolder" is never called for some odd reason, I have log in there , it is never called. My my listeners are alse fine.