Siddharth Siddharth - 2 years ago 115
Android Question

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

sid sid
Answer Source

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!!!

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download