Android 中的适配器、定时器和并发性

Adapter, Timer and concurrency in Android

主要目标:android 用于与公司支持聊天的应用程序消息。

任务: 在列表视图中实现等待操作员或客户端响应的计时器。

问题:在所有列表视图项目中呈现所有计时器之一,然后应用程序正在列出一些计时器,暂时呈现正确结果,但当它们重叠时。

视觉上你可以在这里看到https://drive.google.com/file/d/0B_SjoeZavdZwdXlUQlU3QTVKeG8/view?usp=sharing]1

代码:

 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) {
                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));
        }
    }

}

呜..年..真的不容易.. 这是我的解决..也许它会在未来帮助任何人..

import android.content.Context;
import android.os.Handler;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import ru.pinspb.pinsupport.R;
import ru.pinspb.pinsupport.common.Constants;
import ru.pinspb.pinsupport.pojo.Message;
import ru.pinspb.pinsupport.pojo.SessionInterface;
import ru.pinspb.pinsupport.utils.Helpers;

public class SessionAdapter extends RecyclerView.Adapter<SessionAdapter.Holder> {

    public interface OnItemClickListener {
        void onItemClick(SessionInterface item);
    }

    private static final String TAG = SessionAdapter.class.toString();
    private final OnItemClickListener listener;
    List<SessionInterface> sessions = new ArrayList<>();
    Context context;
    private Message mLastMessage;
    private Handler mHandler = new Handler();

    public SessionAdapter(List<SessionInterface> sessions, Context context, OnItemClickListener listener) {
        this.sessions = sessions;
        this.context = context;
        this.listener = listener;
    }

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

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

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

    @Override
    public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_sessions, null);
        return new Holder(v);
    }

    @Override
    public void onBindViewHolder(final Holder holder, int position) {

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

        holder.bind(session, listener);

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


        try {
            SimpleDateFormat ru = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", new Locale("ru"));
            ru.setTimeZone(TimeZone.getTimeZone("GMT+03:00"));
            Date jud = ru.parse(mLastMessage.getDate());
            String targetFormat = new SimpleDateFormat("d MMMM, HH:mm", new Locale("ru")).format(jud);
            final long milliseconds = jud.getTime();
            holder.date.setText(targetFormat);

            if(session.getClosedTimeAgo() == null) {
                startUpdateTimer(new Runnable() {
                    @Override
                    public void run() {
                        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Europe/Moscow"));
                        Date currentDate = calendar.getTime();
                        holder.updateTimeRemaining(currentDate.getTime(), milliseconds);
                    }
                });
//                Log.d(TAG, "Sid: " + session.getId() + " ;\nnow: " + System.currentTimeMillis() + ";\n last date: " + mLastMessage.getDate() + "; \nmill: " + 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();
        } else {
            if(mLastMessage.getSender_type().equals(Constants.CLIENT_TYPE)) {
                holder.setClientWaiting();
            } else {
                holder.setOperatorWaiting();
            }
        }
    }

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

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

    public long getPositionById(long id) {
        for (int i = 1; i < sessions.size(); i++) {
            long sessionId = getItemId(i);
            boolean eq = id == sessionId;
            if(eq) {
                return i;
            }
        }
        return 0;
    }

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

    public static class Holder extends RecyclerView.ViewHolder {
        TextView label;
        TextView sessionTitle;
        TextView date;
        TextView message;
        TextView status;
        ImageView chatStatusImage;
        TextView timeRemaining;

        public Holder(View itemView) {
            super(itemView);
            this.label = (TextView) itemView.findViewById(R.id.label);
            this.sessionTitle = (TextView) itemView.findViewById(R.id.ticket_title);
            this.date = (TextView) itemView.findViewById(R.id.date);
            this.message = (TextView) itemView.findViewById(R.id.comment);
            this.status = (TextView) itemView.findViewById(R.id.status);
            this.chatStatusImage = (ImageView) itemView.findViewById(R.id.ticket_status);
            this.timeRemaining = (TextView) itemView.findViewById(R.id.time_remaining);
        }

        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;
            long seconds = TimeUnit.MILLISECONDS.toSeconds(timeDiff) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeDiff));
            String time = String.format("%d:%s",
                    TimeUnit.MILLISECONDS.toMinutes(timeDiff),
                    seconds < 10 ? seconds + "0" : String.valueOf(seconds)
            );
            timeRemaining.setText(time);
        }

        public void setClosed() {
            this.status.setText("closed");
            this.status.setTextColor(itemView.getResources().getColor(R.color.closedText));
            this.chatStatusImage.setImageDrawable(itemView.getResources().getDrawable(R.drawable.chat_status_closed));
        }

        public void setOperatorWaiting() {
            this.status.setText("some text");
            this.status.setTextColor(itemView.getResources().getColor(R.color.clientColor));
            this.timeRemaining.setTextColor(itemView.getResources().getColor(R.color.clientColor));
            this.chatStatusImage.setImageDrawable(itemView.getResources().getDrawable(R.drawable.chat_status_client));
        }

        public void setClientWaiting() {
            this.status.setText("some text");
            this.status.setTextColor(itemView.getResources().getColor(R.color.operatorColor));
            this.timeRemaining.setTextColor(itemView.getResources().getColor(R.color.operatorColor));
            this.chatStatusImage.setImageDrawable(itemView.getResources().getDrawable(R.drawable.chat_status_operator));
        }

        public void bind(final SessionInterface item, final OnItemClickListener listener) {
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    listener.onItemClick(item);
                }
            });
        }
    }

}