Wazy
Wazy

Reputation: 494

Firestore how to retrieve data from firestore in recycler view

Background

My app allows users to post images in specific categories and then allows users to tap on the posts to bring up a messaging activity

Problem

I currently have it setup so it is a global chat (any user could join and it was the same between all posts reading and writing from the same document) for testing purposes but I want to have it so it is a private chat between the two users. This was created using the real-time database I am in the process of migrating over to Firestore so I will also have to change the code for the "chatActivity"

What I have done

When the post is created it adds a new document to the messages collection for that post. The messages document name associated with that post is then stored in the post.

Where I am stuck

In my chat activity, I need to be able to get the id of the post so I can then retrieve the location of the document containing the messages related to that post

Objective

To be able to have the users post an image and have a document in the "Messages" collection be created DONE, then to have a second user come and see said image tap on it and then be able to open that document that was created for the image so the two users can then exchange messages between each other making it private between the two users because they are only reading from the document associated with that post

app workflow this should clear up any confusion

Database: database

Code for writing post to database:

filePath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                                @Override
                                public void onSuccess(Uri uri) {
                                    final String downloadUrl =
                                            uri.toString();
                                    Log.d("tag", downloadUrl);

                                    FirebaseUser current_user = FirebaseAuth.getInstance().getCurrentUser();
                                    String uid = Objects.requireNonNull(current_user).getUid();

                                    final Map<String, Object> postMap = new HashMap<>();
                                    // No thumb ?????
                                    postMap.put("image_url", downloadUrl);
                                    postMap.put("desc", desc);
                                    postMap.put("user_id", current_user_id);
                                    postMap.put("message Doc", uid + postCategory);
                                    postMap.put("timestamp", FieldValue.serverTimestamp());


                                    firebaseFirestore.collection(postCategory).add(postMap).addOnCompleteListener(new OnCompleteListener<DocumentReference>() {
                                        @Override
                                        public void onComplete(@NonNull Task<DocumentReference> task) {

                                            if (task.isSuccessful()) {

                                                firebaseFirestore.collection("Posts").add(postMap).addOnCompleteListener(new OnCompleteListener<DocumentReference>() {
                                                    @Override
                                                    public void onComplete(@NonNull Task<DocumentReference> task) {

                                                        FirebaseUser current_user = FirebaseAuth.getInstance().getCurrentUser();
                                                        String uid = Objects.requireNonNull(current_user).getUid();

                                                        final Map<String, String> chatMap = new HashMap<>();
                                                        postMap.put("timestamp", FieldValue.serverTimestamp());
                                                        postMap.put("name", current_user_id);
                                                        postMap.put("message", "");

                                                        firebaseFirestore.collection("Messages")
                                                                .document(uid + postCategory)
                                                                .set(chatMap)
                                                                .addOnSuccessListener(new OnSuccessListener<Void>() {
                                                                    @Override
                                                                    public void onSuccess(Void aVoid) {

                                                                    }
                                                                });

Code for chat

public class ChatActivity extends AppCompatActivity {

    public static final int DEFAULT_MSG_LENGTH_LIMIT = 1000;
    private static final int GALLERY_PICK = 1;

    private ListView mMessageListView;
    private MessageAdapter mMessageAdapter;// This is to do with the file messageadapter\
    private ProgressBar mProgressBar;
    private ImageButton mPhotoPickerButton;
    private EditText mMessageEditText;
    private Button mSendButton;
    private String mUsername;
    private FirebaseDatabase mFirebaseDatabase;
    private DatabaseReference mMessagedatabaseReference;
    private ChildEventListener mChildEventListner;
    private ValueEventListener mValueEventListner;
    private FirebaseUser mCurrentUser;
    private FirebaseStorage mFirebaseStorage;
    private ProgressDialog mProgressDialog;
    private StorageReference mChatPhotosStorageReference;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chat_activity);

        mFirebaseDatabase = FirebaseDatabase.getInstance();
        mMessagedatabaseReference = mFirebaseDatabase.getReference().child("messages");


        //new shit

        // Map<String, Object> usersChat = new HashMap<>();
        // usersChat.put("user 1 id", mCurrentUser);
        // usersChat.put("user2Id", )





        mFirebaseStorage = FirebaseStorage.getInstance();
        mChatPhotosStorageReference = mFirebaseStorage.getReference().child("chat_photos");

        // Initialize references to views
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
        mMessageListView = (ListView) findViewById(R.id.messageListView);
        mPhotoPickerButton = (ImageButton) findViewById(R.id.photoPickerButton);
        mMessageEditText = (EditText) findViewById(R.id.messageEditText);
        mSendButton = (Button) findViewById(R.id.sendButton);

        mCurrentUser = FirebaseAuth.getInstance().getCurrentUser();
        final String current_uid = mCurrentUser.getUid();

        // Initialize progress bar
        mProgressBar.setVisibility(ProgressBar.INVISIBLE);

        //Initialize message ListView and its adapter
        List<FriendlyMessage> friendlyMessages = new ArrayList<>();
        mMessageAdapter = new MessageAdapter(this, R.layout.item_message, friendlyMessages);
        mMessageListView.setAdapter(mMessageAdapter);

        // ImagePickerButton shows an image picker to upload a image for a message
        mPhotoPickerButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent galleryIntent = new Intent();
                galleryIntent.setType("image/*");
                galleryIntent.setAction(Intent.ACTION_GET_CONTENT);

                startActivityForResult(Intent.createChooser(galleryIntent, "Select Image"), GALLERY_PICK);
            }
        });

        // Enable Send button when there's text to send
        mMessageEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (charSequence.toString().trim().length() > 0) {
                    mSendButton.setEnabled(true);
                } else {
                    mSendButton.setEnabled(false);
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {
            }
        });
        mMessageEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(DEFAULT_MSG_LENGTH_LIMIT)});

        // Send button sends a message and clears the EditText
        mSendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FriendlyMessage friendlyMessage = new FriendlyMessage(mMessageEditText.getText().toString());
                mMessagedatabaseReference.push().setValue(friendlyMessage);

                // Clear input box
                mMessageEditText.setText("");
            }
        });

        mChildEventListner = new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
                FriendlyMessage friendlyMessage = dataSnapshot.getValue(FriendlyMessage.class);
                mMessageAdapter.add(friendlyMessage);

            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

            }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        };
        mMessagedatabaseReference.addChildEventListener(mChildEventListner);

        mSendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FriendlyMessage friendlyMessage = new FriendlyMessage(mMessageEditText.getText().toString(), current_uid, null);
                mMessagedatabaseReference.push().setValue(friendlyMessage);

                // Clear input box
                mMessageEditText.setText("");
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == GALLERY_PICK && resultCode == RESULT_OK) {

            Uri selectedImageUri = data.getData();

            final StorageReference photoRef = mChatPhotosStorageReference.child(selectedImageUri.getLastPathSegment());

            photoRef.putFile(selectedImageUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                    photoRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                        @Override
                        public void onSuccess(Uri uri) {
                            String downloadUrl = uri.toString();
                            Log.d("tag", downloadUrl);
                            FriendlyMessage friendlyMessage = new FriendlyMessage(null, mUsername, downloadUrl);
                            mMessagedatabaseReference.push().setValue(friendlyMessage);
                        }
                    });
                }
            });

        }
    }

Upvotes: 1

Views: 6180

Answers (2)

Engels Immanuel
Engels Immanuel

Reputation: 113

Stop stressing yourself writing these boiler plate for retrieving data from firestore to recycler view. Take a look at Firebase UI for Cloud Firestore. Firebase UI for Cloud Firestore makes it simple to bind data from Cloud Firestore to your app's UI, thereby reducing boiler plate and may even help fix your problem. Add this- implementation 'com.firebaseui:firebase-ui-firestore:6.2.1' to dependency to use Firebase UI for Cloud Firestore

Upvotes: 0

Bill Gates
Bill Gates

Reputation: 225

Where I Am Stuck

In my chat activity, I need to be able to get the id of the post so I can then retrieve the location of the document containing the messages related to that post

i am not sure, do you want to get all id or only one id ?

if you want to get the ALL id document of music collection from firestore, please add this in Your code:

public void loadAlltQueries(){
 Query loadAllQueryId = firebaseFirestore
                       .collection("music")
                       .orderBy("timestamp", Query.Direction.DESCENDING);

  loadAllQueryId.addSnapshotListener(new EventListener<QuerySnapshot>(){
    @Override
    public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e){


     for (DocumentChange doc : documentSnapshots.getDocumentChanges()){

       if (doc.getType() == DocumentChange.Type.ADDED){

          String musicId = doc.getDocument().getId();
          FriendlyMessage friendlyMessage = doc.getDocument().toObject(FriendlyMessage.class).withId(musicId);                        

          mMessageAdapter.add(friendlyMessage);                                                                       

          mMessageAdapter.notifyDataSetChanged(); //for update adapter
        }
     }

    }
  });
}

and make MusicId.class

public class MusicId{

    @Exclude
    public String MusicId;

    public <T extends MusicId> T withId(@NonNull final String id) {

        this.MusicId = id;
        return (T) this;
    }

}

don't forget to add this in Your FriendlyMessage.class

public class FriendlyMessage extends MusicId {

// your constructor
// your getter

}

and from your adapter class get your getter

 final String musicId = contentList.get(position).MusicId;

and Now you get your id CHur40Nr ..

if You are looking to get the id of the post that corresponds with whatever post was selected from the recycler view. Please make Adapter class, because holder method will get your post which you selected in this case holder for holder.setMessage(message);

public class AdapterFriendlyMessage extends RecyclerView.Adapter<FriendlyMessage.ViewHolder> {

    public List<FriendlyMessage> contentList;
    public Context context;

    private FirebaseFirestore firebaseFirestore;
    private FirebaseAuth firebaseAuth;

    public AdapterFriendlyMessage(List<FriendlyMessage> contentList){
        this.contentList = contentList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.content_friendly_message, parent, false);
        context = parent.getContext(); FriendlyMessage(container.getContext(), contentList);

        firebaseFirestore = FirebaseFirestore.getInstance();
        firebaseAuth = FirebaseAuth.getInstance();

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {

        holder.setRecyclable(false);

        // GET MusicId
        final String  musicId = contentList.get(position). MusicId;
        final String currentUserId = firebaseAuth.getCurrentUser().getUid();   


        String uid = contentList.get(position).getUid();
        firebaseFirestore.collection(" Music").document( musicId).collection("FriendlyMessage").get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>(){
            @Override
            public void onComplete(@NonNull Task<DocumentSnapshot> task){

                if (task.isSuccessful()) {

                    String message = task.getResult().getString("message");
                    holder.setMessage(message); // this is what you want
                } 
            }
        });       
    }

    @Override
    public int getItemCount() {
        return contentList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        private View mView;    

        private TextView txtMessage;           

        public ViewHolder(View itemView){
            super(itemView);
            mView = itemView;   

        }

            public void setMessage(Sting text) {

                txtMessage = mView.findViewById(R.id.text_view_mesage);
                txtMessage.setText(text);
            }


    }
}

don't forget to passing id from firestore into Adapter public class FriendlyMessageRoom extends Fragment {

private RecyclerView recyclerMessage;
private List<FriendlyMessage > contentList;
private AdapterFriendlyMessage adapterFriendlyMessage;        

private FirebaseFirestore firebaseFirestore;
private FirebaseAuth mAuth;



public FriendlyMessageRoom() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_friendly_message_room, container, false);


    mAuth = FirebaseAuth.getInstance();
    firebaseFirestore = FirebaseFirestore.getInstance();

    contentList = new ArrayList<>();
    recyclerMessage = view.findViewById(R.id.recycler_message);
    adapterFriendlyMessage = new AdapterFriendlyMessage(contentList);
    recyclerMessage.setLayoutManager(new LinearLayoutManager(container.getContext()));
    recyclerMessage.setAdapter(adapterFriendlyMessage);

    return view;
}

@Override
public void onStart() {
    super.onStart();

    loadAlltQueries(); // please see firebase query that i write above
}

NOTE: my this answer might not answer your question accurately, since it hard to imagine what you want in the problem description.

Upvotes: 3

Related Questions