androidquickblox-android

count on chat does not working correctly QuickBlox


I am using quickblox for my android application. I am able to register, login user, even add custom objects and retrieve them from the quick-blox server, but in chatting listing screen my count is coming wrong.

I am getting issue with unread count

Here is my code flow:-

public class ConversationFragment extends Fragment implements Observer, DialogsManager.ManagingDialogsCallbacks {
    ConversationViewModel conversationViewModel;
    FragmentConversationBinding binding;
    QBChatDialogMessageListener allDialogsMessagesListener;
    SystemMessagesListener systemMessagesListener;
    QBSystemMessagesManager systemMessagesManager;
    QBIncomingMessagesManager incomingMessagesManager;
    private DialogsManager dialogsManager;

    public ConversationFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_conversation, container, false);
        getActivity().getWindow().setBackgroundDrawableResource(R.drawable.bg_img);
        View view = binding.getRoot();
        systemMessagesListener = new SystemMessagesListener();
        dialogsManager = new DialogsManager();

        return view;
    }

    private void setUpModel() {
        Bundle mBundle = getArguments();
        if (mBundle != null) {
            conversationViewModel = new ConversationViewModel(getActivity(), binding, getArguments().getString("DialogIdData"));
        } else {
            conversationViewModel = new ConversationViewModel(getActivity(), binding, "");
        }

        binding.setConversationViewModel(conversationViewModel);
        setUpObserver(conversationViewModel);

    }


    private void setUpObserver(ConversationViewModel observer) {
        observer.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
    }

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

    }

    @Override
    public void onResume() {
        super.onResume();
        setUpModel();

    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterQbChatListeners();
    }


    public void unregisterQbChatListeners() {
        if (incomingMessagesManager != null) {
            incomingMessagesManager.removeDialogMessageListrener(allDialogsMessagesListener);
        }

        if (systemMessagesManager != null) {
            systemMessagesManager.removeSystemMessageListener(systemMessagesListener);
        }
        dialogsManager.removeManagingDialogsCallbackListener(this);
    }

    @Override
    public void onDialogCreated(QBChatDialog chatDialog) {
    }

    @Override
    public void onDialogUpdated(String chatDialog) {

    }

    @Override
    public void onNewDialogLoaded(QBChatDialog chatDialog) {

    }

    private class SystemMessagesListener implements QBSystemMessageListener {
        @Override
        public void processMessage(final QBChatMessage qbChatMessage) {
            dialogsManager.onSystemMessageReceived(qbChatMessage);
        }

        @Override
        public void processError(QBChatException e, QBChatMessage qbChatMessage) {

        }
    }

    private BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
        }
    };


}

Here is my Fragment viewModel code :-

public class ConversationViewModel extends Observable implements DialogsManager.ManagingDialogsCallbacks {
    private static final int REQUEST_DIALOG_ID_FOR_UPDATE = 165;
    public Context mContext;
    FragmentConversationBinding binding;
    private ActionMode currentActionMode;
    public QBRequestGetBuilder requestBuilder;
    private int skipRecords = 0;
    private DialogsAdapter dialogsAdapter;
    private QBChatDialogMessageListener allDialogsMessagesListener;
    private SystemMessagesListener systemMessagesListener;
    private QBSystemMessagesManager systemMessagesManager;
    private QBIncomingMessagesManager incomingMessagesManager;
    private DialogsManager dialogsManager;
    private QBUser currentUser;
    private String id;

    public ConversationViewModel(Context mContext, FragmentConversationBinding binding, String Dialogid) {
        this.mContext = mContext;
        this.binding = binding;
        this.id = Dialogid;
        initUI();
    }

    public void initUI() {
        allDialogsMessagesListener = new AllDialogsMessageListener();
        systemMessagesListener = new SystemMessagesListener();
        dialogsManager = new DialogsManager();
        currentUser = ChatHelper.getCurrentUser();
        initList();
        registerQbChatListeners();
        if (QbDialogHolder.getInstance().getDialogs().size() > 0) {
            loadDialogsFromQb(true, true);
        } else {
            loadDialogsFromQb(false, true);
        }
        if (!id.isEmpty()) {
            loadUpdatedDialog(id);
            id = "";
        } else {
            updateDialogsList();
        }
    }

    public void initList() {
        dialogsAdapter = new DialogsAdapter(mContext, new ArrayList<>(QbDialogHolder.getInstance().getDialogs().values()));
        binding.listDialogsChats.setAdapter(dialogsAdapter);
        binding.listDialogsChats.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                QBChatDialog selectedDialog = (QBChatDialog) parent.getItemAtPosition(position);
                if (currentActionMode == null) {
                    ChatActivity.startForResult(((Activity) mContext), REQUEST_DIALOG_ID_FOR_UPDATE, selectedDialog);
                } else {
                    dialogsAdapter.toggleSelection(selectedDialog);
                }
            }
        });
        binding.listDialogsChats.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                QBChatDialog selectedDialog = (QBChatDialog) parent.getItemAtPosition(position);
                dialogsAdapter.selectItem(selectedDialog);
                return true;
            }
        });
        requestBuilder = new QBRequestGetBuilder();
        binding.swipyRefreshLayout.setOnRefreshListener(new SwipyRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh(SwipyRefreshLayoutDirection direction) {
                requestBuilder.setSkip(skipRecords += ChatHelper.DIALOG_ITEMS_PER_PAGE);
                loadDialogsFromQb(true, false);
            }
        });


    }

    private void loadUpdatedDialog(String dialogId) {
        ChatHelper.getInstance().getDialogById(dialogId, new QbEntityCallbackImpl<QBChatDialog>() {
            @Override
            public void onSuccess(QBChatDialog result, Bundle bundle) {
                QbDialogHolder.getInstance().addDialog(result);
                updateDialogsAdapter();
            }

            @Override
            public void onError(QBResponseException e) {

            }
        });
    }

    public void updateDialogsList() {
        requestBuilder.setSkip(skipRecords = 0);
        loadDialogsFromQb(true, true);
    }

    @Override
    public void onDialogCreated(QBChatDialog chatDialog) {
        updateDialogsAdapter();
    }

    @Override
    public void onDialogUpdated(String chatDialog) {
        updateDialogsAdapter();
    }

    @Override
    public void onNewDialogLoaded(QBChatDialog chatDialog) {
        updateDialogsAdapter();
    }


    private void registerQbChatListeners() {
        incomingMessagesManager = QBChatService.getInstance().getIncomingMessagesManager();
        systemMessagesManager = QBChatService.getInstance().getSystemMessagesManager();

        if (incomingMessagesManager != null) {
            incomingMessagesManager.addDialogMessageListener(allDialogsMessagesListener != null
                    ? allDialogsMessagesListener : new AllDialogsMessageListener());
        }

        if (systemMessagesManager != null) {
            systemMessagesManager.addSystemMessageListener(systemMessagesListener != null
                    ? systemMessagesListener : new SystemMessagesListener());
        }

        dialogsManager.addManagingDialogsCallbackListener(this);
    }


    private class SystemMessagesListener implements QBSystemMessageListener {
        @Override
        public void processMessage(final QBChatMessage qbChatMessage) {
            dialogsManager.onSystemMessageReceived(qbChatMessage);
        }

        @Override
        public void processError(QBChatException e, QBChatMessage qbChatMessage) {

        }
    }

    private class AllDialogsMessageListener extends QbChatDialogMessageListenerImp {
        @Override
        public void processMessage(final String dialogId, final QBChatMessage qbChatMessage, Integer senderId) {
            if (!senderId.equals(ChatHelper.getCurrentUser().getId())) {
                dialogsManager.onGlobalMessageReceived(dialogId, qbChatMessage);
            }
        }
    }

    public void updateDialogsAdapter() {
        dialogsAdapter.updateList(new ArrayList<>(QbDialogHolder.getInstance().getDialogs().values()));
    }

    public void loadDialogsFromQb(final boolean silentUpdate, final boolean clearDialogHolder) {
        if (!silentUpdate) {
            binding.progressDialogs.setVisibility(View.VISIBLE);
        }

        ChatHelper.getInstance().getDialogs(requestBuilder, new QBEntityCallback<ArrayList<QBChatDialog>>() {
            @Override
            public void onSuccess(ArrayList<QBChatDialog> dialogs, Bundle bundle) {
                binding.progressDialogs.setVisibility(View.GONE);
                binding.swipyRefreshLayout.setRefreshing(false);
                if (clearDialogHolder) {
                    QbDialogHolder.getInstance().clear();
                }
                QbDialogHolder.getInstance().addDialogs(dialogs);
                updateDialogsAdapter();
            }

            @Override
            public void onError(QBResponseException e) {
                binding.progressDialogs.setVisibility(View.GONE);
                binding.swipyRefreshLayout.setRefreshing(false);
                Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }
}

Here is my Chat Activity:-

public class ChatActivity extends BindingActivity<ActivityChatBinding> implements OnImagePickedListener {
    ChatViewModel chatViewModel;
    public static final int REQUEST_CODE_ATTACHMENT = 721;
    public static final String EXTRA_DIALOG_ID = "dialogId";

    @Override
    protected int getLayoutId() {
        return R.layout.activity_chat;
    }

    public static void startForResult(Activity activity, int code, QBChatDialog dialogId) {
        Intent intent = new Intent(activity, ChatActivity.class);
        intent.putExtra(ChatActivity.EXTRA_DIALOG_ID, dialogId);
        activity.startActivityForResult(intent, code);
    }

    @Override
    public void setInitBinding() {
        getWindow().setBackgroundDrawableResource(R.drawable.bg_img);
        chatViewModel = new ChatViewModel(this, binding);
        binding.setChatViewModel(chatViewModel);
    }

    @Override
    protected void setUpObserver() {
        chatViewModel.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
    }

    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
    }

    @Override
    public void onBackPressed() {
        binding.getChatViewModel().releaseChat();
        binding.getChatViewModel().sendDialogId();
        super.onBackPressed();
    }

    @Override
    public void onImagePicked(int requestCode, File file) {
        switch (requestCode) {
            case REQUEST_CODE_ATTACHMENT:
                binding.getChatViewModel().attachmentPreviewAdapter.add(file);
                break;
        }
    }

    @Override
    public void onImagePickError(int requestCode, Exception e) {
        Toast.makeText(this, e.toString(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onImagePickClosed(int requestCode) {

    }

}

Chat Activity View Model :-

public class ChatViewModel extends Observable {
    public Context mContext;
    ActivityChatBinding binding;
    public static final String TAG = ChatActivity.class.getSimpleName();
    public static final int REQUEST_CODE_ATTACHMENT = 721;
    public static final String PROPERTY_SAVE_TO_HISTORY = "save_to_history";
    public static final String EXTRA_DIALOG_ID = "dialogId";
    public ChatAdapter chatAdapter;
    public AttachmentPreviewAdapter attachmentPreviewAdapter;
    public QBChatDialog qbChatDialog;
    public ArrayList<QBChatMessage> unShownMessages;
    public int skipPagination = 0;
    public ChatMessageListener chatMessageListener;
    QBPrivacyList qbPrivacyList;
    public static boolean mBlock;
    public static int userId, recipientId;
    public QBPrivacyListsManager privacyListsManager;
    public ObservableField<String> chatMessage = new ObservableField<>("");

    public ChatViewModel(Context mContext, ActivityChatBinding binding) {
        this.mContext = mContext;
        this.binding = binding;
        Log.v(TAG, "onCreate ChaActivity on Thread ID = " + Thread.currentThread().getId());
        qbChatDialog = (QBChatDialog) ((Activity) mContext).getIntent().getSerializableExtra(EXTRA_DIALOG_ID);

        Log.v(TAG, "deserialized dialog = " + qbChatDialog);
        qbChatDialog.initForChat(QBChatService.getInstance());
        chatMessageListener = new ChatMessageListener();
        qbPrivacyList = new QBPrivacyList();
        privacyListsManager = QBChatService.getInstance().getPrivacyListsManager();
        qbChatDialog.addMessageListener(chatMessageListener);
        initViews();
        initChat();
    }


    public void initViews() {
        try {
            recipientId = qbChatDialog.getRecipientId();
            userId = qbChatDialog.getUserId();
            getPrivacyList();
        } catch (SmackException.NotConnectedException e) {
            e.printStackTrace();
        } catch (XMPPException.XMPPErrorException e) {
            e.printStackTrace();
        } catch (SmackException.NoResponseException e) {
            e.printStackTrace();
        }
        attachmentPreviewAdapter = new AttachmentPreviewAdapter(mContext,
                new AttachmentPreviewAdapter.OnAttachmentCountChangedListener() {
                    @Override
                    public void onAttachmentCountChanged(int count) {
                        binding.attachmentContainer.setVisibility(count == 0 ? View.GONE : View.VISIBLE);
                    }
                },
                new AttachmentPreviewAdapter.OnAttachmentUploadErrorListener() {
                    @Override
                    public void onAttachmentUploadError(QBResponseException e) {
                        Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
                    }
                });
        binding.attachmentAdapter.setAdapter(attachmentPreviewAdapter);


    }

    public void onAttachmentsClick(View view) {
        new ImagePickHelper().pickAnImage(((FragmentActivity) mContext), REQUEST_CODE_ATTACHMENT);
    }

    private void initChat() {
        switch (qbChatDialog.getType()) {
            case PRIVATE:
                loadDialogUsers();
                break;

            default:
                Toaster.shortToast(String.format("%s %s", getString(R.string.chat_unsupported_type), qbChatDialog.getType().name()));
                ((Activity) mContext).finish();
                break;
        }
    }


    public void loadDialogUsers() {
        ChatHelper.getInstance().getUsersFromDialog(qbChatDialog, new QBEntityCallback<ArrayList<QBUser>>() {
            @Override
            public void onSuccess(ArrayList<QBUser> users, Bundle bundle) {
                String chatName = QbDialogUtils.getDialogName(qbChatDialog);
                binding.dialogName.setText(chatName);
                loadChatHistory();
            }

            @Override
            public void onError(QBResponseException e) {
                Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void loadChatHistory() {
        ChatHelper.getInstance().loadChatHistory(qbChatDialog, skipPagination, new QBEntityCallback<ArrayList<QBChatMessage>>() {
            @Override
            public void onSuccess(ArrayList<QBChatMessage> messages, Bundle args) {
                Collections.reverse(messages);
                if (chatAdapter == null) {
                    chatAdapter = new ChatAdapter(mContext, qbChatDialog, messages);
                    chatAdapter.setPaginationHistoryListener(new PaginationHistoryListener() {
                        @Override
                        public void downloadMore() {
                            loadChatHistory();
                        }
                    });
                    chatAdapter.setOnItemInfoExpandedListener(new ChatAdapter.OnItemInfoExpandedListener() {
                        @Override
                        public void onItemInfoExpanded(final int position) {
                            if (isLastItem(position)) {
                                ((Activity) mContext).runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        binding.listChat.setSelection(position);
                                    }
                                });
                            } else {
                                binding.listChat.smoothScrollToPosition(position);
                            }
                        }

                        private boolean isLastItem(int position) {
                            return position == chatAdapter.getCount() - 1;
                        }
                    });
                    if (unShownMessages != null && !unShownMessages.isEmpty()) {
                        List<QBChatMessage> chatList = chatAdapter.getList();
                        for (QBChatMessage message : unShownMessages) {
                            if (!chatList.contains(message)) {
                                chatAdapter.add(message);
                            }
                        }
                    }
                    binding.listChat.setAdapter(chatAdapter);
                    binding.listChat.setAreHeadersSticky(false);
                    binding.listChat.setDivider(null);
                } else {
                    chatAdapter.addList(messages);
                    binding.listChat.setSelection(messages.size());
                }
                binding.progressBar.setVisibility(View.GONE);
            }

            @Override
            public void onError(QBResponseException e) {
                binding.progressBar.setVisibility(View.GONE);
                skipPagination -= ChatHelper.CHAT_HISTORY_ITEMS_PER_PAGE;
                Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
            }
        });
        skipPagination += ChatHelper.CHAT_HISTORY_ITEMS_PER_PAGE;

        QBRestChatService.markMessagesAsRead(qbChatDialog.getDialogId(), null);

    }


    public class ChatMessageListener extends QbChatDialogMessageListenerImp {
        @Override
        public void processMessage(String s, QBChatMessage qbChatMessage, Integer integer) {
            showMessage(qbChatMessage);
        }
    }

    public void showMessage(QBChatMessage message) {
        if (chatAdapter != null) {
            chatAdapter.add(message);
            scrollMessageListDown();
        } else {
            if (unShownMessages == null) {
                unShownMessages = new ArrayList<>();
            }
            unShownMessages.add(message);
        }
    }


    public void scrollMessageListDown() {
        binding.listChat.setSelection(binding.listChat.getCount() - 1);
    }

    public void onSendChatClick(View view) {
        int totalAttachmentsCount = attachmentPreviewAdapter.getCount();
        Collection<QBAttachment> uploadedAttachments = attachmentPreviewAdapter.getUploadedAttachments();
        if (!uploadedAttachments.isEmpty()) {
            if (uploadedAttachments.size() == totalAttachmentsCount) {
                for (QBAttachment attachment : uploadedAttachments) {
                    sendChatMessage(null, attachment);
                }
            } else {
                Toaster.shortToast(R.string.chat_wait_for_attachments_to_upload);
            }
        }

        String text = binding.getChatViewModel().chatMessage.get().trim();
        if (!TextUtils.isEmpty(text)) {
            sendChatMessage(text, null);
        }
    }

    public void sendChatMessage(String text, QBAttachment attachment) {
        QBChatMessage chatMessage = new QBChatMessage();
        if (attachment != null) {
            chatMessage.addAttachment(attachment);
        } else {
            chatMessage.setBody(text);
        }
        chatMessage.setProperty(PROPERTY_SAVE_TO_HISTORY, "1");
        chatMessage.setDateSent(System.currentTimeMillis() / 1000);
        chatMessage.setMarkable(true);

        if (!QBDialogType.PRIVATE.equals(qbChatDialog.getType()) && !qbChatDialog.isJoined()) {
            Toaster.shortToast("You're still joining a group chat, please wait a bit");
            return;
        }

        try {
            qbChatDialog.sendMessage(chatMessage);

            if (QBDialogType.PRIVATE.equals(qbChatDialog.getType())) {
                showMessage(chatMessage);
            }

            if (attachment != null) {
                attachmentPreviewAdapter.remove(attachment);
            } else {
                binding.getChatViewModel().chatMessage.set("");
            }
        } catch (SmackException.NotConnectedException e) {
            Log.w(TAG, e);
            Toaster.shortToast("Can't send a message, You are not connected to chat");
        }
    }

    public void leaveGroupDialog() {
        try {
            ChatHelper.getInstance().leaveChatDialog(qbChatDialog);
        } catch (XMPPException | SmackException.NotConnectedException e) {
            Log.w(TAG, e);
        }
    }

    public void releaseChat() {
        qbChatDialog.removeMessageListrener(chatMessageListener);
        if (!QBDialogType.PRIVATE.equals(qbChatDialog.getType())) {
            leaveGroupDialog();
        }
    }

    public void sendDialogId() {
        Intent result = new Intent();
        result.putExtra(EXTRA_DIALOG_ID, qbChatDialog.getDialogId());
        ((Activity) mContext).setResult(RESULT_OK, result);
    }

    public void finishActivity(View view) {
        ((Activity) mContext).finish();
    }

    public void clickButtonBlock(View view) {
        AppUtils.dialog(mContext);
        if (mBlock) {
            onClickUnblock();
        } else {
            onClickBlock();
        }
    }

    public void getPrivacyList() throws SmackException.NotConnectedException, XMPPException.XMPPErrorException, SmackException.NoResponseException {
        QBPrivacyListsManager privacyListsManager = QBChatService.getInstance().getPrivacyListsManager();
        QBPrivacyList privacyList = privacyListsManager.getPrivacyList("public");
        List<QBPrivacyListItem> items = privacyList.getItems();
        int i;
        for (i = 0; i < privacyList.getItems().size(); i++) {
            QBPrivacyListItem item = items.get(i);
            String valueForType = item.getValueForType();
            String[] splitvalueType = valueForType.split("-");
            String blockId = splitvalueType[0];
            if (blockId.equalsIgnoreCase(String.valueOf(recipientId))) {
                mBlock = true;
                binding.tvBlock.setText("Unblock");
                break;
            } else {
                binding.tvBlock.setText("Block");
            }
        }
    }

}

The problem is chatDialog.getUnreadMessageCount() giving me count 2 when I once enter in chat room and come back to my chat listing page.

Description on issue:-

Example:- I have installed my application in two devices. when i send message from one (Device A) to other (Device B).The device B will display correct Unread count i.e 1 . Now when i click on chat dialog and get entered inside the chat room (of Device B). and come back to it's listing page and then again try to send message from Device A to device B . This time the unread count comes as 2 but it should be one as i already viewed my previous message. This get more worse if i try to open my chat room again to read the message(Device B) and get back to my listing page(Device B) after reading the message . This time if I send the message from Device A to Device B, Then the count came out as "5" just for my one message this thing is making me sick, I debugged the whole code, it's chatDialog .getUnreadMessageCount() who is returning me count "5", I don't know why my previous messages are not counted as being read messages and why everytime I open chat room one additional number gets added up inside the unread count.Please help me out , i am scratching my head from past two days.

Your help will be greatly Appreciated.

Thanks


Solution

  • Problem is that your AllDialogsMessageListener is not getting unregistered so unregister it by calling unregisterQbChatListeners(); when you will be opening your chat room screen . Every thing will work fine once you do that.

    This what i mean :-

    binding.listDialogsChats.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    QBChatDialog selectedDialog = (QBChatDialog) parent.getItemAtPosition(position);
                    if (currentActionMode == null) {
                        unregisterQbChatListeners();
                        ChatActivity.startForResult(((Activity) mContext), REQUEST_DIALOG_ID_FOR_UPDATE, selectedDialog);
                    } else {
                        dialogsAdapter.toggleSelection(selectedDialog);
                    }
                }
            });
    
    private void unregisterQbChatListeners() {
            if (incomingMessagesManager != null) {
                incomingMessagesManager.removeDialogMessageListrener(allDialogsMessagesListener);
            }
    
            if (systemMessagesManager != null) {
                systemMessagesManager.removeSystemMessageListener(systemMessagesListener);
            }
    
            dialogsManager.removeManagingDialogsCallbackListener(this);
        }
    

    cheers!!!