Адаптер, таймеры и многопоточность. Android.
Алексей Скробот

Всем привет! Столкнулся со следующей проблемой:
Общий таск: android приложение-мессенджер для общения с саппортом интернет-провайдера.
Трабла: Необходимо реализовать в списке чатов таймеры отсчета ожидания ответа оператора и клиента.
Что происходит: Проблема с мултипоточностью - один поток перекрывает рендеринг всех остальных.
Нагдяно можно посмотреть тут: https://drive.google.com/file/d/0B_SjoeZavdZwdXlUQlU3QTVKeG8/view?usp=sharing
Где посмотреть код: https://gist.github.com/scrobot/3e8e0b8874707f671bb792eed63f8fea

Для ленивых - выкладываю гифку и код здесь)
https://imgflip.com/gif/13meq5

public class SessionAdapter extends BaseAdapter {

    private static final String TAG = SessionAdapter.class.toString();
    List<SessionInterface> sessions = new ArrayList<>();
    Context context;
    private Message mLastMessage;
    private List<ViewHolder> lstHolders;
    private Handler mHandler = new Handler();
    private Runnable updateRemainingTimeRunnable = new Runnable() {
        @Override
        public void run() {
            synchronized (lstHolders) {
                long currentTime = System.currentTimeMillis();
                for (ViewHolder holder : lstHolders) {
                    holder.updateTimeRemaining(currentTime, 0);
                }
            }
        }
    };

    public SessionAdapter(List<SessionInterface> sessions, Context context) {
        this.sessions = sessions;
        this.context = context;
        lstHolders = new ArrayList<>();
        startUpdateTimer();
    }

    public void updateSessions(List<SessionInterface> sessionInterface) {
        this.sessions = sessionInterface;
    }

    @Override
    public int getCount() {
        return sessions.size();
    }

    @Override
    public SessionInterface getItem(int position) {
        return sessions.get(position);
    }

    @Override
    public long getItemId(int position) {
        SessionInterface session = sessions.get(position);
        return session.getId();
    }

    public long getPositionById(long id) {
        for (int i = 1; i < sessions.size(); i++) {
            long sessionId = getItemId(i);
            Log.d(TAG, "getPositionById-i: " + i);
            Log.d(TAG, "getPositionById-id: " + id);
            Log.d(TAG, "getPositionById-sessionId: " + sessionId);
            boolean eq = id == sessionId;
            Log.d(TAG, "getPositionById-sessionId==id: " + eq);
            if(eq) {
                return i;
            }
        }
        return 0;
    }

    private void startUpdateTimer() {
        Timer tmr = new Timer();
        tmr.schedule(new TimerTask() {
            @Override
            public void run() {
                mHandler.post(updateRemainingTimeRunnable);
            }
        }, 1000, 1000);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        final SessionInterface session = sessions.get(position);
        ViewHolder holder;
        mLastMessage = session.getMessages().get(session.getMessages().size() - 1);


        if(convertView == null) {
            holder = new ViewHolder();
            convertView = LayoutInflater.from(context).inflate(R.layout.adapter_sessions, null);
            holder.label = (TextView) convertView.findViewById(R.id.label);
            holder.sessionTitle = (TextView) convertView.findViewById(R.id.ticket_title);
            holder.date = (TextView) convertView.findViewById(R.id.date);
            holder.message = (TextView) convertView.findViewById(R.id.comment);
            holder.status = (TextView) convertView.findViewById(R.id.status);
            holder.chatStatusImage = (ImageView) convertView.findViewById(R.id.ticket_status);
            holder.timeRemaining = (TextView) convertView.findViewById(R.id.time_remaining);
            convertView.setTag(holder);
            synchronized (lstHolders) {
                lstHolders.add(holder);
            }
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.label.setText("Чат #" + session.getId());
        holder.sessionTitle.setText(Helpers.stringLimit(session.getQueue().getName(), 30));

        try {
            Date jud = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", new Locale("ru")).parse(mLastMessage.getDate());
            String targetFormat = new SimpleDateFormat("d MMMM, HH:mm", new Locale("ru")).format(jud);
            long milliseconds = jud.getTime();
            holder.date.setText(targetFormat);
            if(session.getClosedTimeAgo() == null) {
//                Log.d(TAG, "Sid: " + session.getId() + " ;\nnow: " + System.currentTimeMillis() + ";\n last date: " + mLastMessage.getDate() + "; \nmill: " + milliseconds );
                holder.updateTimeRemaining(System.currentTimeMillis(), milliseconds);
                holder.timeRemaining.setVisibility(View.VISIBLE);
            } else {
                holder.timeRemaining.setVisibility(View.GONE);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }

        holder.message.setText(Helpers.stringLimit(Helpers.stripLineBreaks(mLastMessage.getText(), " "), 50));

        if(session.getIs_closed() == 1) {
            holder.setClosed(convertView);
        } else {
            if(mLastMessage.getSender_type().equals(Constants.CLIENT_TYPE)) {
                holder.setClientWaiting(convertView);
            } else {
                holder.setOperatorWaiting(convertView);
            }
        }

        return convertView;

    }

    private class ViewHolder {
        TextView label;
        TextView sessionTitle;
        TextView date;
        TextView message;
        TextView status;
        ImageView chatStatusImage;
        TextView timeRemaining;

        public void updateTimeRemaining(long currentTime, long timeAgo) {
            Log.d(TAG, "updateTimeRemaining:\n currentTime - " + currentTime + ";\n timeAgo - " + timeAgo + ";\n timeDiff(currentTime - timeAgo) = " + (currentTime - timeAgo));
            Log.d(TAG, "updateTimeRemaining:\n currentTime - " + currentTime + ";\n timeAgo - " + timeAgo + ";\n timeDiff(timeAgo - currentTime) = " + (timeAgo - currentTime));
            long timeDiff = currentTime - timeAgo;
            if (timeDiff > 0) {
                int seconds = (int) (timeDiff / 1000) % 60;
                int minutes = (int) ((timeDiff / (1000 * 60)) % 60);
                int hours = (int) ((timeDiff / (1000 * 60 * 60)) % 24);
                int hourMinutes = hours*60 + minutes;
                timeRemaining.setText(hourMinutes + ":" + (seconds < 10 ? "0" + seconds : seconds));
            } else {
                timeRemaining.setText("Expired!!");
            }
        }

        public void setClosed(View convertView) {
            this.status.setText("Закрыто");
            this.status.setTextColor(convertView.getResources().getColor(R.color.closedText));
            this.chatStatusImage.setImageDrawable(convertView.getResources().getDrawable(R.drawable.chat_status_closed));
        }

        public void setOperatorWaiting(View convertView) {
            this.status.setText("Оператор ожидает ваш ответ");
            this.status.setTextColor(convertView.getResources().getColor(R.color.clientColor));
            this.timeRemaining.setTextColor(convertView.getResources().getColor(R.color.clientColor));
            this.chatStatusImage.setImageDrawable(convertView.getResources().getDrawable(R.drawable.chat_status_client));
        }

        public void setClientWaiting(View convertView) {
            this.status.setText("Ожидается ответ оператора");
            this.status.setTextColor(convertView.getResources().getColor(R.color.operatorColor));
            this.timeRemaining.setTextColor(convertView.getResources().getColor(R.color.operatorColor));
            this.chatStatusImage.setImageDrawable(convertView.getResources().getDrawable(R.drawable.chat_status_operator));
        }
    }

}

Помогите решить эту проблемку, пожалуйста)) Заранее спасибо за ваши ответы!)

2 чел.