'Image doesn't send for other side Android Studio java

I have problem, because I can't send images for other side, it duplicates or sends empty message, but normal messages work fine. I've tried many tutorials and changing some classes, but nothing really worked

here's my recycler view class:

public final class ChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private final List<ChatMessage> messages;
    private Bitmap profileImage;
    private final String senderId;

    private static final int VIEW_TYPE_SENT = 1;
    private static final int VIEW_TYPE_RECEIVED = 2;

    public void setReceiverProfileImage(Bitmap bitmap) {
        this.profileImage = bitmap;
    }

    public ChatAdapter(List<ChatMessage> messages, Bitmap profileImage, String senderId) {
        this.messages = messages;
        this.profileImage = profileImage;
        this.senderId = senderId;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return (viewType == VIEW_TYPE_SENT ? new SentMessageViewHolder(
                ItemContainerSentMessageBinding.inflate(
                        LayoutInflater.from(parent.getContext()),
                        parent,
                        false)
        ) : new ReceivedMessageViewHolder(
                ItemContainerReceivedMessageBinding.inflate(
                        LayoutInflater.from(parent.getContext()),
                        parent,
                        false)
        ));
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (getItemViewType(position) == VIEW_TYPE_SENT) {
            ((SentMessageViewHolder) holder).setData(messages.get(position));
        } else {
            ((ReceivedMessageViewHolder) holder).setData(messages.get(position), profileImage);
        }

    }

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

    @Override
    public int getItemViewType(int position) {
        return (messages.get(position).getSenderId().equals(senderId) ? VIEW_TYPE_SENT : VIEW_TYPE_RECEIVED);
    }

    public static class SentMessageViewHolder extends RecyclerView.ViewHolder {

        private final ItemContainerSentMessageBinding binding;

        public SentMessageViewHolder(ItemContainerSentMessageBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        void setData(ChatMessage message) {
            binding.textMessage.setText(message.getMessage());
            binding.textDateTime.setText(message.getDateTime());
            binding.image.setImageBitmap(message.getImage());
        }
    }

    public static class ReceivedMessageViewHolder extends RecyclerView.ViewHolder {

        private final ItemContainerReceivedMessageBinding binding;

        public ReceivedMessageViewHolder(ItemContainerReceivedMessageBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        void setData(ChatMessage message, Bitmap bitmap) {
            binding.textMessage.setText(message.getMessage());
            binding.textDateTime.setText(message.getDateTime());
            if (bitmap != null) {
                binding.imageProfile.setImageBitmap(bitmap);
            }
            binding.image.setImageBitmap(message.getImage());
        }
    }
}

Here's received message:

<com.makeramen.roundedimageview.RoundedImageView
        android:id="@+id/imageProfile"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:background="@drawable/background_image"
        android:scaleType="centerCrop"
        app:layout_constraintBottom_toBottomOf="@id/textMessage"
        app:layout_constraintStart_toStartOf="parent"
        app:riv_oval="true"/>

    <TextView
        android:id="@+id/textMessage"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="4dp"
        android:layout_marginLeft="4dp"
        android:background="@drawable/background_received_message"
        android:paddingStart="12dp"
        android:paddingEnd="12dp"
        android:paddingTop="8dp"
        android:paddingBottom="8dp"
        app:layout_constraintWidth_max="wrap"
        android:textColor="@color/white"
        android:textSize="13sp"
        app:layout_constraintStart_toEndOf="@id/imageProfile"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_percent="0.75"/>

    <ImageView
        android:id="@+id/image"
        android:background="@drawable/background_sent_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:layout_marginStart="4dp"
        android:maxWidth="250dp"
        android:maxHeight="250dp"
        app:layout_constraintStart_toEndOf="@id/imageProfile"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/textDateTime"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:textColor="@color/secondary_text"
        android:textSize="8sp"
        app:layout_constraintStart_toStartOf="@id/textMessage"
        app:layout_constraintTop_toBottomOf="@id/textMessage"/>

and picking image activity:

    private final ActivityResultLauncher<Intent> pickImage = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
        if (result.getResultCode() != RESULT_OK) return;
        if (result.getData() == null) return;
        Uri imageUri = result.getData().getData();

        try {
            InputStream inputStream = getContentResolver().openInputStream(imageUri);
            Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
            this.encodingImage = encodeImage(bitmap);
            sendMessage();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    });

and here create ChatMessage object (eventListener):

    private final EventListener<QuerySnapshot> eventListener = (value, error) -> {
        if (error != null) {
            return;
        }
        if (value != null) {
            int count = messages.size();
            for (DocumentChange documentChange : value.getDocumentChanges()) {
                if (documentChange.getType() == DocumentChange.Type.ADDED) {
                    ChatMessage chatMessage = new ChatMessage(
                            documentChange.getDocument().getString(Constants.KEY_SENDER_ID),
                            documentChange.getDocument().getString(Constants.KEY_RECEIVER_ID),
                            documentChange.getDocument().getString(Constants.KEY_MESSAGE),
                            getReadableDateTime(documentChange.getDocument().getDate(Constants.KEY_TIMESTAMP)),
                            documentChange.getDocument().getDate(Constants.KEY_TIMESTAMP)
                    );
                    if (!encodingImage.isEmpty()) {
                        byte[] decodedString = Base64.decode(encodingImage, Base64.DEFAULT);
                        Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
                        chatMessage.setImage(decodedByte);
                    }
                    messages.add(chatMessage);
                }
            }
            Collections.sort(messages, Comparator.comparing(ChatMessage::getDate));
            if (count == 0) {
                chatAdapter.notifyDataSetChanged();
            } else {
                chatAdapter.notifyItemRangeInserted(messages.size(), messages.size());
                binding.chatRecyclerView.smoothScrollToPosition(messages.size() - 1);
            }
            binding.chatRecyclerView.setVisibility(View.VISIBLE);
        }
        binding.progressBar.setVisibility(View.GONE);
        if (conversionId == null) checkForConversion();
    };

sendMessage method:

    private void sendMessage() {
        Map<String, Object> message = new HashMap<>();
        message.put(Constants.KEY_SENDER_ID, preferenceManager.getString(Constants.KEY_USER_ID));
        message.put(Constants.KEY_RECEIVER_ID, user.getId());
        message.put(Constants.KEY_MESSAGE, binding.inputMessage.getText().toString());
        if (!encodingImage.isEmpty()) {
            message.put(Constants.KEY_IMAGE_MESSAGE, encodingImage);
        }
        message.put(Constants.KEY_TIMESTAMP, new Date());
        db.collection(Constants.KEY_COLLECTION_CHAT).add(message);
        if (conversionId != null) {
            updateConversion(binding.inputMessage.getText().toString());
        } else {
            Map<String, Object> conversion = new HashMap<>();
            conversion.put(Constants.KEY_SENDER_ID, preferenceManager.getString(Constants.KEY_USER_ID));
            conversion.put(Constants.KEY_SENDER_NAME, preferenceManager.getString(Constants.KEY_NAME));
            conversion.put(Constants.KEY_SENDER_IMAGE, preferenceManager.getString(Constants.KEY_IMAGE));

            conversion.put(Constants.KEY_RECEIVER_ID, user.getId());
            conversion.put(Constants.KEY_RECEIVER_NAME, user.getName());
            conversion.put(Constants.KEY_RECEIVER_IMAGE, user.getImage());
            conversion.put(Constants.KEY_LAST_MESSAGE, binding.inputMessage.getText().toString());
            conversion.put(Constants.KEY_TIMESTAMP, new Date());
            addConversion(conversion);
        }
        if (!isReceiverAvaible) {
            try {
                JSONArray tokens = new JSONArray();
                tokens.put(user.getToken());

                JSONObject data = new JSONObject();
                data.put(Constants.KEY_USER_ID, preferenceManager.getString(Constants.KEY_USER_ID));
                data.put(Constants.KEY_NAME, preferenceManager.getString(Constants.KEY_NAME));
                data.put(Constants.KEY_FCM_TOKEN, preferenceManager.getString(Constants.KEY_FCM_TOKEN));
                data.put(Constants.KEY_MESSAGE, binding.inputMessage.getText().toString());

                JSONObject body = new JSONObject();
                body.put(Constants.REMOTE_MSG_DATA, data);
                body.put(Constants.REMOTE_MSG_REGISTRATION_IDS, tokens);

                sendNotification(body.toString());

            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        binding.inputMessage.setText(null);
    }

listenMessages method:

    private void listenMessages() {
        db.collection(Constants.KEY_COLLECTION_CHAT)
                .whereEqualTo(Constants.KEY_SENDER_ID, preferenceManager.getString(Constants.KEY_USER_ID))
                .whereEqualTo(Constants.KEY_RECEIVER_ID, user.getId())
                .addSnapshotListener(eventListener);
        db.collection(Constants.KEY_COLLECTION_CHAT)
                .whereEqualTo(Constants.KEY_SENDER_ID, user.getId())
                .whereEqualTo(Constants.KEY_RECEIVER_ID, preferenceManager.getString(Constants.KEY_USER_ID))
                .addSnapshotListener(eventListener);
    }
    private String encodeImage(Bitmap bitmap) {
        int previewWidth = 300;
        int previewHeight = bitmap.getHeight() * previewWidth / bitmap.getWidth();
        Bitmap previewBitmap = Bitmap.createScaledBitmap(bitmap, previewWidth, previewHeight, false);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        previewBitmap.compress(Bitmap.CompressFormat.JPEG, 50, byteArrayOutputStream);
        return Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.DEFAULT);
    }

Please help and thanks!



Solution 1:[1]

The issue


You are actually providing the adapter the encodingImage which was just created and that is why you get repeated or no image at all.

The solution

There are 2 parts in this solution:

  1. Reformat the methods and their parameters
  2. Change the code to pick image for sending image

Let's start !

1. Reformat the methods and their parameters

First of all, you need to add 1 parameter to the sendMessage() method. It will look something like this:

private void sendMessage(String encodedImage) {
        Map<String, Object> message = new HashMap<>();
        message.put(Constants.KEY_SENDER_ID, preferenceManager.getString(Constants.KEY_USER_ID));
        message.put(Constants.KEY_RECEIVER_ID, user.getId());
        message.put(Constants.KEY_MESSAGE, binding.inputMessage.getText().toString());
        message.put(Constants.KEY_IMAGE_MESSAGE, encodedImage);
        message.put(Constants.KEY_TIMESTAMP, new Date());
        db.collection(Constants.KEY_COLLECTION_CHAT).add(message);
        if (conversionId != null) {
            updateConversion(binding.inputMessage.getText().toString());
        } else {
            Map<String, Object> conversion = new HashMap<>();
            conversion.put(Constants.KEY_SENDER_ID, preferenceManager.getString(Constants.KEY_USER_ID));
            conversion.put(Constants.KEY_SENDER_NAME, preferenceManager.getString(Constants.KEY_NAME));
            conversion.put(Constants.KEY_SENDER_IMAGE, preferenceManager.getString(Constants.KEY_IMAGE));

            conversion.put(Constants.KEY_RECEIVER_ID, user.getId());
            conversion.put(Constants.KEY_RECEIVER_NAME, user.getName());
            conversion.put(Constants.KEY_RECEIVER_IMAGE, user.getImage());
            conversion.put(Constants.KEY_LAST_MESSAGE, binding.inputMessage.getText().toString());
            conversion.put(Constants.KEY_TIMESTAMP, new Date());
            addConversion(conversion);
        }
        if (!isReceiverAvaible) {
            try {
                JSONArray tokens = new JSONArray();
                tokens.put(user.getToken());

                JSONObject data = new JSONObject();
                data.put(Constants.KEY_USER_ID, preferenceManager.getString(Constants.KEY_USER_ID));
                data.put(Constants.KEY_NAME, preferenceManager.getString(Constants.KEY_NAME));
                data.put(Constants.KEY_FCM_TOKEN, preferenceManager.getString(Constants.KEY_FCM_TOKEN));
                data.put(Constants.KEY_MESSAGE, binding.inputMessage.getText().toString());

                JSONObject body = new JSONObject();
                body.put(Constants.REMOTE_MSG_DATA, data);
                body.put(Constants.REMOTE_MSG_REGISTRATION_IDS, tokens);

                sendNotification(body.toString());

            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        binding.inputMessage.setText(null);
    }

Now after this, you need to change the eventListener object. It will look like this:

private final EventListener<QuerySnapshot> eventListener = (value, error) -> {
        if (error != null) {
            return;
        }
        if (value != null) {
            int count = messages.size();
            for (DocumentChange documentChange : value.getDocumentChanges()) {
                if (documentChange.getType() == DocumentChange.Type.ADDED) {
                    ChatMessage chatMessage = new ChatMessage(
                            documentChange.getDocument().getString(Constants.KEY_SENDER_ID),
                            documentChange.getDocument().getString(Constants.KEY_RECEIVER_ID),
                            documentChange.getDocument().getString(Constants.KEY_MESSAGE),
                            getReadableDateTime(documentChange.getDocument().getDate(Constants.KEY_TIMESTAMP)),
                            documentChange.getDocument().getDate(Constants.KEY_TIMESTAMP)
                    );
                    if (documentChange.getDocument().getString(Constants.KEY_IMAGE_MESSAGE) != null && !documentChange.getDocument().getString(Constants.KEY_IMAGE_MESSAGE).isEmpty()) {
                        byte[] decodedString = Base64.decode((documentChange.getDocument().getString(Constants.KEY_IMAGE_MESSAGE, Base64.DEFAULT);
                        Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
                        chatMessage.setImage(decodedByte);
                    }
                    messages.add(chatMessage);
                }
            }
            Collections.sort(messages, Comparator.comparing(ChatMessage::getDate));
            if (count == 0) {
                chatAdapter.notifyDataSetChanged();
            } else {
                chatAdapter.notifyItemRangeInserted(messages.size(), messages.size());
                binding.chatRecyclerView.smoothScrollToPosition(messages.size() - 1);
            }
            binding.chatRecyclerView.setVisibility(View.VISIBLE);
        }
        binding.progressBar.setVisibility(View.GONE);
        if (conversionId == null) checkForConversion();
    };

2. Change the code to pick image for sending image

Now you are doing a very very wrong thing while trying to send an image method. This issue start's from the place where you are picking the image. To solve it, replace that with this code:

private final ActivityResultLauncher<Intent> pickImage = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
        if (result.getResultCode() != RESULT_OK) return;
        if (result.getData() == null) return;
        Uri imageUri = result.getData().getData();

        try {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
            sendMessage(encodeImage(bitmap));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    });

Also you need to change the encodeImage method now!:

private String encodeImage(Bitmap bitmap) {
        int previewWidth = 300;
        int previewHeight = bitmap.getHeight() * previewWidth / bitmap.getWidth();
        Bitmap previewBitmap = Bitmap.createScaledBitmap(bitmap, previewWidth, previewHeight, false);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        previewBitmap.compress(Bitmap.CompressFormat.JPEG, 50, byteArrayOutputStream);
        String str = Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.DEFAULT);
        return str == null ? "" : str;
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1