Search code examples
androidandroid-arrayadapter

In Android how to prevent updating existing items on notifyDataSetChanged()


I have chat app In custom array adapter. I set random colors to usernames for each message with this code:

String[] array = context.getResources().getStringArray(R.array.username_colors);
randomColor = array[new Random().nextInt(array.length)];
nameTextView.setTextColor(Color.parseColor(randomColor));

When new message arrive I add it to listview, and call adapter.notifyDataSetChanged(); This causes recoloring existing usernames in messages each time. How can I prevent recoloring existing items in listview when calling adapter.notifyDataSetChanged();

Edit 1

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ChatMessageElement el = list.get(position);
        ViewHolder holder = null;
        NewMessagesLabelHolder labelHolder = null;

        if (convertView == null) {
            convertView = el.getView(inflater, parent);

            if (el.isMessage()) {

                holder = new ViewHolder();
                holder.messageLayout = (RelativeLayout) convertView.findViewById(R.id.message_container);
                holder.messageContent = (LinearLayout) convertView.findViewById(R.id.message_content);
                holder.bottomIndicator = (LinearLayout) convertView.findViewById(R.id.bottom_indicators);
                holder.dateTextView = (TextView) convertView.findViewById(R.id.message_date);
                holder.timeAgo = (TextView) convertView.findViewById(R.id.time_ago);
                holder.nameTextView = (TextView) convertView.findViewById(R.id.user_name);
                holder.likesCountTextView = (TextView) convertView.findViewById(R.id.likes_count);
                holder.likesLabelImageView = (ImageView) convertView.findViewById(R.id.likes_label);
                holder.spamCountTextView = (TextView) convertView.findViewById(R.id.spam_count);
                holder.spamLabelImageView = (ImageView) convertView.findViewById(R.id.spam_label);
                holder.avatarImageView = (ImageView) convertView.findViewById(R.id.avatar);
                holder.statusImageView = (ImageView) convertView.findViewById(R.id.delivered_label);
                holder.progressBar = (ProgressBar) convertView.findViewById(R.id.progress_bar);
                holder.errorSign = (ImageView) convertView.findViewById(R.id.error_sign);
                holder.spamSign = (ImageView) convertView.findViewById(R.id.spam_sign);
                holder.bookmarkLabel = (ImageView) convertView.findViewById(R.id.bookmark_label);
                holder.topIndicators = (LinearLayout) convertView.findViewById(R.id.topIndicators);
                convertView.setTag(holder);
            }
            if (el.isNewMessagesLabel()) {
                convertView = inflater.inflate(R.layout.chat_new_messages_label_layout, parent, false);

                labelHolder = new NewMessagesLabelHolder();
                labelHolder.newMessagesLabel = (TextView) convertView.findViewById(R.id.new_messages_label);
                convertView.setTag(labelHolder);
            }
        } else {
            if (el.isMessage()) {
                holder = (ViewHolder) convertView.getTag();
            }
            if (el.isNewMessagesLabel()) {
                labelHolder = (NewMessagesLabelHolder) convertView.getTag();
            }
        }

        if (el.isMessage()) {
            Message currentMessage = (Message) el;
            drawMessage(holder, currentMessage, position);
        }
        if (el.isNewMessagesLabel()) {
            NewMessagesLabel messagesLabel = (NewMessagesLabel) el;
            drawNewMessagesLabel(labelHolder, messagesLabel);
        }

        return convertView;
    }



private void drawMessage(ViewHolder holder, Message message, int position) {
        String date = message.getCreatedAt();
        String formattedDate = DateHelper.getInstance(context).formatDate("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "HH:mm", date);

        String userName = message.getUserName();

        holder.likesLabelImageView.setVisibility(View.GONE);
        holder.likesCountTextView.setVisibility(View.GONE);
        holder.spamCountTextView.setVisibility(View.GONE);
        holder.spamLabelImageView.setVisibility(View.GONE);
        holder.bookmarkLabel.setVisibility(View.GONE);
        holder.statusImageView.setVisibility(View.GONE);
        holder.progressBar.setVisibility(View.GONE);
        holder.statusImageView.setVisibility(View.GONE);
        holder.errorSign.setVisibility(View.GONE);
        holder.spamSign.setVisibility(View.GONE);
        holder.timeAgo.setVisibility(View.GONE);
        holder.timeAgo.setText("");
        holder.messageLayout.setAlpha(1f);
        holder.topIndicators.setVisibility(View.VISIBLE);

        if (message.isNewDay()) {
            holder.timeAgo.setVisibility(View.VISIBLE);
            String dayDate = DateHelper.getInstance(context).formatDate("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "MMMM d, yyyy", date);
            //String dayDate = getTimeAgo(mHelper.millisFromString(message.getCreatedAt()), context);
            holder.timeAgo.setText(dayDate);
        }else{
            holder.timeAgo.setVisibility(View.GONE);
        }

        holder.avatarImageView.setImageResource(R.drawable.com_facebook_profile_default_icon);

        if (GrouviDatabaseManager.getInstance(context).getCurrentUser().getId() == message.getUserId()) {
            userName = USERNAME_ME;


            if (message.getStatus() != null && message.getStatus().equals(Message.MSG_STATUS_SEND)) {
                holder.statusImageView.setBackgroundResource(R.drawable.icon_chat_message_delivered);
                holder.statusImageView.setVisibility(View.VISIBLE);
            }
            if (message.getStatus() != null && message.getStatus().equals(Message.MSG_STATUS_SENDING)) {
                holder.progressBar.setVisibility(View.VISIBLE);
            }
            if (message.getStatus() != null && message.getStatus().equals(Message.MSG_STATUS_LOCAL)) {
                holder.statusImageView.setBackgroundResource(R.drawable.icon_chat_message_delivered);
                holder.statusImageView.setVisibility(View.VISIBLE);
            }
            if (message.getStatus() == null || message.getStatus().equals(Message.MSG_STATUS_ERROR)) {
                holder.messageLayout.setAlpha(0.4f);
                holder.errorSign.setVisibility(View.VISIBLE);
            }
        }


        if (message.getSpamCount() > 0 && currentMode == MODE_NORMAL) {
            holder.messageLayout.setAlpha(0.4f);
            holder.spamSign.setVisibility(View.VISIBLE);
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            holder.messageContent.setLayoutParams(params);

            holder.spamCountTextView.setText(Integer.toString(message.getSpamCount()));
            holder.spamCountTextView.setVisibility(View.VISIBLE);
            holder.spamLabelImageView.setVisibility(View.VISIBLE);
        } else {
            holder.messageLayout.setAlpha(1f);
            holder.spamSign.setVisibility(View.GONE);
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            holder.messageContent.setLayoutParams(params);
        }

        if (currentMode == MODE_REPORT) {
            String timeAgo = getTimeAgo(mHelper.millisFromString(message.getCreatedAt()));
            holder.timeAgo.setText(timeAgo);
            holder.timeAgo.setVisibility(View.VISIBLE);
        }

        if (message.getUserAvatar() != null && !message.getUserAvatar().isEmpty()) {
            try {
                Picasso
                        .with(context)
                        .load(message.getUserAvatar())
                        .error(R.drawable.com_facebook_profile_default_icon)
                        .placeholder(R.drawable.com_facebook_profile_default_icon)
                        .into(holder.avatarImageView);
            } catch (Exception e) {
                Log.e("Main", e.getMessage(), e);
            }
        }
        colorUsername(holder, message, userName);
        holder.nameTextView.setText(userName);
        holder.dateTextView.setText(formattedDate);

        if (message.getLikesCount()>0) {
            holder.likesCountTextView.setText(Integer.toString(message.getLikesCount()));
            holder.likesCountTextView.setVisibility(View.VISIBLE);
            holder.likesLabelImageView.setVisibility(View.VISIBLE);
        }

        if (message.isBookmarked()) {
            holder.bookmarkLabel.setVisibility(View.VISIBLE);
        }

        List<MessageComponent> messageComponentList;
        messageComponentList = message.getMessageComponents();

        drawMessageContent(holder, messageComponentList, message);

        holder.nameTextView.setTag(position);
        holder.avatarImageView.setTag(position);
        holder.nameTextView.setOnClickListener(userClickListener);
        holder.avatarImageView.setOnClickListener(userClickListener);

        // hang empty onLingClickListener to display context menu when
        // long click on whole message
        holder.nameTextView.setOnLongClickListener(longClickListener);
        holder.avatarImageView.setOnLongClickListener(longClickListener);
    }

private void colorUsername(ViewHolder holder, Message message, String userName) {
        String randomColor = prevColor;
        if (userName.equals(USERNAME_ME)){
            randomColor = "#000000";
        }else if (message.getUserId()!=prevMsgUserID) {
            do {
                String[] array = context.getResources().getStringArray(R.array.username_colors);
                randomColor = array[new Random().nextInt(array.length)];
            }while (prevColor.equals(randomColor));

        }
        holder.nameTextView.setTextColor(Color.parseColor(randomColor));
        prevColor = randomColor;
        prevMsgUserID = message.getUserId();
    }

Solution

  • You should keep color in the data class, for example in the Message class, or keep Map in the adapter, that maps Message to Color. Then randomly create a color, when it doesn't present in the map. or use the color, if it present in the map. Using a map is good solution than keeping in the data class, when the color doesn't related to message, when it is not a message property, so in that case, a good solution is a keeping it in the adapter class, in the map, for example

        private Map<Message, String> colorsMap = new HashMap<Message, String>();
    
    private void colorUsername(ViewHolder holder, Message message, String userName) {
        String randomColor;
        if(colorsMap.contains(message)) {
            randomColor = colorsMap.get(message);
        }
        else {
            if (userName.equals(USERNAME_ME)){
                randomColor = "#000000";
            }else if (message.getUserId()!=prevMsgUserID) {
                do {
                    String[] array = context.getResources().getStringArray(R.array.username_colors);
                    randomColor = array[new Random().nextInt(array.length)];
                }while (prevColor.equals(randomColor));
    
            }
            colorsMap.put(message, randomColor);
        }        
        holder.nameTextView.setTextColor(Color.parseColor(randomColor));
    }