環信UI開源Demo情景分析十二、聊天界面(四)
來源:程序員人生 發布時間:2015-05-04 09:49:11 閱讀次數:6243次
在這1章我們來分析1下聊天界面中消息的顯示,MessageAdapter。
public MessageAdapter(Context context, String username, int chatType) {
this.username = username;
this.context = context;
inflater = LayoutInflater.from(context);
activity = (Activity) context;
this.conversation = EMChatManager.getInstance().getConversation(username);
}
其中構造方法中是對成員變量的賦值。
并且在適配器里面還聲明了1個Handler:
Handler handler = new Handler() {
private void refreshList() {
// UI線程不能直接使用conversation.getAllMessages()
// 否則在UI刷新進程中,如果收到新的消息,會致使并提問題
messages = (EMMessage[]) conversation.getAllMessages().toArray(new EMMessage[conversation.getAllMessages().size()]);
for (int i = 0; i < messages.length; i++) {
// getMessage will set message as read status
conversation.getMessage(i);
}
notifyDataSetChanged();
}
@Override
public void handleMessage(android.os.Message message) {
switch (message.what) {
case HANDLER_MESSAGE_REFRESH_LIST:
refreshList();
break;
case HANDLER_MESSAGE_SELECT_LAST:
if (activity instanceof ChatActivity) {
ListView listView = ((ChatActivity) activity).getListView();
if (messages.length > 0) {
listView.setSelection(messages.length - 1);
}
}
break;
case HANDLER_MESSAGE_SEEK_TO:
int position = message.arg1;
if (activity instanceof ChatActivity) {
ListView listView = ((ChatActivity) activity).getListView();
listView.setSelection(position);
}
break;
default:
break;
}
}
};
當傳遞過來的消息為HANDLER_MESSAGE_REFRESH_LIST時,調用refreshList方法刷新UI。當傳遞過來的消息為HANDLER_MESSAGE_SELECT_LAST時,將ListVIew轉動到最后1項。當傳遞過來的消息為HANDLER_MESSAGE_SEEK_TO時,將ListView轉動到指定位置。 /**
* 獲得item數
*/
public int getCount() {
return messages == null ? 0 : messages.length;
}
如果沒有消息返回0./**
* 刷新頁面
*/
public void refresh() {
if (handler.hasMessages(HANDLER_MESSAGE_REFRESH_LIST)) {
return;
}
android.os.Message msg = handler.obtainMessage(HANDLER_MESSAGE_REFRESH_LIST);
handler.sendMessage(msg);
}
如果Handler中沒有HANDLER_MESSAGE_REFRESH_LIST消息的時候發送此消息。 /**
* 刷新頁面, 選擇最后1個
*/
public void refreshSelectLast() {
handler.sendMessage(handler.obtainMessage(HANDLER_MESSAGE_REFRESH_LIST));
handler.sendMessage(handler.obtainMessage(HANDLER_MESSAGE_SELECT_LAST));
}
/**
* 刷新頁面, 選擇Position
*/
public void refreshSeekTo(int position) {
handler.sendMessage(handler.obtainMessage(HANDLER_MESSAGE_REFRESH_LIST));
android.os.Message msg = handler.obtainMessage(HANDLER_MESSAGE_SEEK_TO);
msg.arg1 = position;
handler.sendMessage(msg);
}
更改UI前先刷新UI。 public EMMessage getItem(int position) {
if (messages != null && position < messages.length) {
return messages[position];
}
return null;
}
public long getItemId(int position) {
return position;
}
Adapter中需要重載的方法。 private static final int MESSAGE_TYPE_RECV_TXT = 0;
private static final int MESSAGE_TYPE_SENT_TXT = 1;
private static final int MESSAGE_TYPE_SENT_IMAGE = 2;
private static final int MESSAGE_TYPE_SENT_LOCATION = 3;
private static final int MESSAGE_TYPE_RECV_LOCATION = 4;
private static final int MESSAGE_TYPE_RECV_IMAGE = 5;
private static final int MESSAGE_TYPE_SENT_VOICE = 6;
private static final int MESSAGE_TYPE_RECV_VOICE = 7;
private static final int MESSAGE_TYPE_SENT_VIDEO = 8;
private static final int MESSAGE_TYPE_RECV_VIDEO = 9;
private static final int MESSAGE_TYPE_SENT_FILE = 10;
private static final int MESSAGE_TYPE_RECV_FILE = 11;
private static final int MESSAGE_TYPE_SENT_VOICE_CALL = 12;
private static final int MESSAGE_TYPE_RECV_VOICE_CALL = 13;
private static final int MESSAGE_TYPE_SENT_VIDEO_CALL = 14;
private static final int MESSAGE_TYPE_RECV_VIDEO_CALL = 15;
/**
* 獲得item類型數
*/
public int getViewTypeCount() {
return 16;
}
獲得消息類型的個數。/**
* 獲得item類型
*/
public int getItemViewType(int position) {
EMMessage message = getItem(position);
if (message == null) {
return ⑴;
}
if (message.getType() == EMMessage.Type.TXT) {
if (message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VOICE_CALL, false))
return message.direct == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_VOICE_CALL : MESSAGE_TYPE_SENT_VOICE_CALL;
else if (message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VIDEO_CALL, false))
return message.direct == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_VIDEO_CALL : MESSAGE_TYPE_SENT_VIDEO_CALL;
return message.direct == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_TXT : MESSAGE_TYPE_SENT_TXT;
}
if (message.getType() == EMMessage.Type.IMAGE) {
return message.direct == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_IMAGE : MESSAGE_TYPE_SENT_IMAGE;
}
if (message.getType() == EMMessage.Type.LOCATION) {
return message.direct == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_LOCATION : MESSAGE_TYPE_SENT_LOCATION;
}
if (message.getType() == EMMessage.Type.VOICE) {
return message.direct == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_VOICE : MESSAGE_TYPE_SENT_VOICE;
}
if (message.getType() == EMMessage.Type.VIDEO) {
return message.direct == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_VIDEO : MESSAGE_TYPE_SENT_VIDEO;
}
if (message.getType() == EMMessage.Type.FILE) {
return message.direct == EMMessage.Direct.RECEIVE ? MESSAGE_TYPE_RECV_FILE : MESSAGE_TYPE_SENT_FILE;
}
return ⑴;// invalid
}
通過SDK來判斷具體是發送的消息還是接收的消息。 private View createViewByMessage(EMMessage message, int position) {
switch (message.getType()) {
case LOCATION:
return message.direct == EMMessage.Direct.RECEIVE ? inflater.inflate(R.layout.row_received_location, null) : inflater.inflate(R.layout.row_sent_location, null);
case IMAGE:
return message.direct == EMMessage.Direct.RECEIVE ? inflater.inflate(R.layout.row_received_picture, null) : inflater.inflate(R.layout.row_sent_picture, null);
case VOICE:
return message.direct == EMMessage.Direct.RECEIVE ? inflater.inflate(R.layout.row_received_voice, null) : inflater.inflate(R.layout.row_sent_voice, null);
case VIDEO:
return message.direct == EMMessage.Direct.RECEIVE ? inflater.inflate(R.layout.row_received_video, null) : inflater.inflate(R.layout.row_sent_video, null);
case FILE:
return message.direct == EMMessage.Direct.RECEIVE ? inflater.inflate(R.layout.row_received_file, null) : inflater.inflate(R.layout.row_sent_file, null);
default:
// 語音通話
if (message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VOICE_CALL, false))
return message.direct == EMMessage.Direct.RECEIVE ? inflater.inflate(R.layout.row_received_voice_call, null) : inflater.inflate(R.layout.row_sent_voice_call, null);
// 視頻通話
else if (message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VIDEO_CALL, false))
return message.direct == EMMessage.Direct.RECEIVE ? inflater.inflate(R.layout.row_received_video_call, null) : inflater.inflate(R.layout.row_sent_video_call, null);
return message.direct == EMMessage.Direct.RECEIVE ? inflater.inflate(R.layout.row_received_message, null) : inflater.inflate(R.layout.row_sent_message, null);
}
}
根據不同的消息類型來創建不同的布局,由于消息內容多是文本、或是視頻等,而且多是發過來的,或是發送出去的。所以要有不同的布局文件。
接下來就是最主要的方法了getView:
public View getView(final int position, View convertView, ViewGroup parent) {
// 獲得具體的消息對象
final EMMessage message = getItem(position);
// 取得消息類型
ChatType chatType = message.getChatType();
// 生命1個holder
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
// 創建該消息的布局
convertView = createViewByMessage(message, position);
if (message.getType() == EMMessage.Type.IMAGE) {
try {
// 消息為圖片格式
holder.iv = ((ImageView) convertView.findViewById(R.id.iv_sendPicture));
holder.iv_avatar = (ImageView) convertView.findViewById(R.id.iv_userhead);
holder.tv = (TextView) convertView.findViewById(R.id.percentage);
holder.pb = (ProgressBar) convertView.findViewById(R.id.progressBar);
holder.staus_iv = (ImageView) convertView.findViewById(R.id.msg_status);
holder.tv_usernick = (TextView) convertView.findViewById(R.id.tv_userid);
} catch (Exception e) {
}
} else if (message.getType() == EMMessage.Type.TXT) {
try {
// 消息為文本格式
holder.pb = (ProgressBar) convertView.findViewById(R.id.pb_sending);
holder.staus_iv = (ImageView) convertView.findViewById(R.id.msg_status);
holder.iv_avatar = (ImageView) convertView.findViewById(R.id.iv_userhead);
// 這里是文字內容
holder.tv = (TextView) convertView.findViewById(R.id.tv_chatcontent);
holder.tv_usernick = (TextView) convertView.findViewById(R.id.tv_userid);
} catch (Exception e) {
}
// 語音通話及視頻通話
if (message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VOICE_CALL, false) || message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VIDEO_CALL, false)) {
holder.iv = (ImageView) convertView.findViewById(R.id.iv_call_icon);
holder.tv = (TextView) convertView.findViewById(R.id.tv_chatcontent);
}
} else if (message.getType() == EMMessage.Type.VOICE) {
// 消息為聲音
try {
holder.iv = ((ImageView) convertView.findViewById(R.id.iv_voice));
holder.iv_avatar = (ImageView) convertView.findViewById(R.id.iv_userhead);
holder.tv = (TextView) convertView.findViewById(R.id.tv_length);
holder.pb = (ProgressBar) convertView.findViewById(R.id.pb_sending);
holder.staus_iv = (ImageView) convertView.findViewById(R.id.msg_status);
holder.tv_usernick = (TextView) convertView.findViewById(R.id.tv_userid);
holder.iv_read_status = (ImageView) convertView.findViewById(R.id.iv_unread_voice);
} catch (Exception e) {
}
} else if (message.getType() == EMMessage.Type.LOCATION) {
try {
// 消息為地理位置
holder.iv_avatar = (ImageView) convertView.findViewById(R.id.iv_userhead);
holder.tv = (TextView) convertView.findViewById(R.id.tv_location);
holder.pb = (ProgressBar) convertView.findViewById(R.id.pb_sending);
holder.staus_iv = (ImageView) convertView.findViewById(R.id.msg_status);
holder.tv_usernick = (TextView) convertView.findViewById(R.id.tv_userid);
} catch (Exception e) {
}
} else if (message.getType() == EMMessage.Type.VIDEO) {
try {
// 消息為視頻文件
holder.iv = ((ImageView) convertView.findViewById(R.id.chatting_content_iv));
holder.iv_avatar = (ImageView) convertView.findViewById(R.id.iv_userhead);
holder.tv = (TextView) convertView.findViewById(R.id.percentage);
holder.pb = (ProgressBar) convertView.findViewById(R.id.progressBar);
holder.staus_iv = (ImageView) convertView.findViewById(R.id.msg_status);
holder.size = (TextView) convertView.findViewById(R.id.chatting_size_iv);
holder.timeLength = (TextView) convertView.findViewById(R.id.chatting_length_iv);
holder.playBtn = (ImageView) convertView.findViewById(R.id.chatting_status_btn);
holder.container_status_btn = (LinearLayout) convertView.findViewById(R.id.container_status_btn);
holder.tv_usernick = (TextView) convertView.findViewById(R.id.tv_userid);
} catch (Exception e) {
}
} else if (message.getType() == EMMessage.Type.FILE) {
try {
// 消息為文件
holder.iv_avatar = (ImageView) convertView.findViewById(R.id.iv_userhead);
holder.tv_file_name = (TextView) convertView.findViewById(R.id.tv_file_name);
holder.tv_file_size = (TextView) convertView.findViewById(R.id.tv_file_size);
holder.pb = (ProgressBar) convertView.findViewById(R.id.pb_sending);
holder.staus_iv = (ImageView) convertView.findViewById(R.id.msg_status);
holder.tv_file_download_state = (TextView) convertView.findViewById(R.id.tv_file_state);
holder.ll_container = (LinearLayout) convertView.findViewById(R.id.ll_file_container);
// 這里是進度值
holder.tv = (TextView) convertView.findViewById(R.id.percentage);
} catch (Exception e) {
}
try {
holder.tv_usernick = (TextView) convertView.findViewById(R.id.tv_userid);
} catch (Exception e) {
}
}
// 設置TAG
convertView.setTag(holder);
} else {
// 獲得TAG
holder = (ViewHolder) convertView.getTag();
}
// 群聊時,顯示接收的消息的發送人的名稱
if (chatType == ChatType.GroupChat && message.direct == EMMessage.Direct.RECEIVE) {
// demo里使用username代碼nick
holder.tv_usernick.setText(message.getFrom());
}
// 如果是發送的消息并且不是群聊消息,顯示已讀textview
if (message.direct == EMMessage.Direct.SEND && chatType != ChatType.GroupChat) {
holder.tv_ack = (TextView) convertView.findViewById(R.id.tv_ack);
holder.tv_delivered = (TextView) convertView.findViewById(R.id.tv_delivered);
if (holder.tv_ack != null) {
if (message.isAcked) {
if (holder.tv_delivered != null) {
holder.tv_delivered.setVisibility(View.INVISIBLE);
}
holder.tv_ack.setVisibility(View.VISIBLE);
} else {
holder.tv_ack.setVisibility(View.INVISIBLE);
// check and display msg delivered ack status
if (holder.tv_delivered != null) {
if (message.isDelivered) {
holder.tv_delivered.setVisibility(View.VISIBLE);
} else {
holder.tv_delivered.setVisibility(View.INVISIBLE);
}
}
}
}
} else {
// 如果是文本或地圖消息并且不是group messgae,顯示的時候給對方發送已讀回執
if ((message.getType() == Type.TXT || message.getType() == Type.LOCATION) && !message.isAcked && chatType != ChatType.GroupChat) {
// 不是語音通話記錄
if (!message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VOICE_CALL, false)) {
try {
EMChatManager.getInstance().ackMessageRead(message.getFrom(), message.getMsgId());
// 發送已讀回執
message.isAcked = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// 設置用戶頭像
setUserAvatar(message, holder.iv_avatar);
switch (message.getType()) {
// 根據消息type顯示item
case IMAGE: // 圖片
handleImageMessage(message, holder, position, convertView);
break;
case TXT: // 文本
if (message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VOICE_CALL, false) || message.getBooleanAttribute(Constant.MESSAGE_ATTR_IS_VIDEO_CALL, false))
// 音視頻通話
handleCallMessage(message, holder, position);
else
handleTextMessage(message, holder, position);
break;
case LOCATION: // 位置
handleLocationMessage(message, holder, position, convertView);
break;
case VOICE: // 語音
handleVoiceMessage(message, holder, position, convertView);
break;
case VIDEO: // 視頻
handleVideoMessage(message, holder, position, convertView);
break;
case FILE: // 1般文件
handleFileMessage(message, holder, position, convertView);
break;
default:
// not supported
}
// 重發
if (message.direct == EMMessage.Direct.SEND) {
View statusView = convertView.findViewById(R.id.msg_status);
// 重發按鈕點擊事件
statusView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 顯示重發消息的自定義alertdialog
Intent intent = new Intent(activity, AlertDialog.class);
intent.putExtra("msg", activity.getString(R.string.confirm_resend));
intent.putExtra("title", activity.getString(R.string.resend));
intent.putExtra("cancel", true);
intent.putExtra("position", position);
if (message.getType() == EMMessage.Type.TXT)
activity.startActivityForResult(intent, ChatActivity.REQUEST_CODE_TEXT);
else if (message.getType() == EMMessage.Type.VOICE)
activity.startActivityForResult(intent, ChatActivity.REQUEST_CODE_VOICE);
else if (message.getType() == EMMessage.Type.IMAGE)
activity.startActivityForResult(intent, ChatActivity.REQUEST_CODE_PICTURE);
else if (message.getType() == EMMessage.Type.LOCATION)
activity.startActivityForResult(intent, ChatActivity.REQUEST_CODE_LOCATION);
else if (message.getType() == EMMessage.Type.FILE)
activity.startActivityForResult(intent, ChatActivity.REQUEST_CODE_FILE);
else if (message.getType() == EMMessage.Type.VIDEO)
activity.startActivityForResult(intent, ChatActivity.REQUEST_CODE_VIDEO);
}
});
} else {
final String st = context.getResources().getString(R.string.Into_the_blacklist);
// 長按頭像,移入黑名單
holder.iv_avatar.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Intent intent = new Intent(activity, AlertDialog.class);
intent.putExtra("msg", st);
intent.putExtra("cancel", true);
intent.putExtra("position", position);
activity.startActivityForResult(intent, ChatActivity.REQUEST_CODE_ADD_TO_BLACKLIST);
return true;
}
});
}
// 時間
TextView timestamp = (TextView) convertView.findViewById(R.id.timestamp);
if (position == 0) {
timestamp.setText(DateUtils.getTimestampString(new Date(message.getMsgTime())));
timestamp.setVisibility(View.VISIBLE);
} else {
// 兩條消息時間離得如果稍長,顯示時間
EMMessage prevMessage = getItem(position - 1);
if (prevMessage != null && DateUtils.isCloseEnough(message.getMsgTime(), prevMessage.getMsgTime())) {
timestamp.setVisibility(View.GONE);
} else {
timestamp.setText(DateUtils.getTimestampString(new Date(message.getMsgTime())));
timestamp.setVisibility(View.VISIBLE);
}
}
return convertView;
}
其中部份說明都已注釋。 /**
* 顯示用戶頭像
*
* @param message
* @param imageView
*/
private void setUserAvatar(EMMessage message, ImageView imageView) {
if (message.direct == Direct.SEND) {
// 顯示自己頭像
UserUtils.setUserAvatar(context, EMChatManager.getInstance().getCurrentUser(), imageView);
} else {
UserUtils.setUserAvatar(context, message.getFrom(), imageView);
}
}
/**
* 文本消息
*
* @param message
* @param holder
* @param position
*/
private void handleTextMessage(EMMessage message, ViewHolder holder, final int position) {
TextMessageBody txtBody = (TextMessageBody) message.getBody();
Spannable span = SmileUtils.getSmiledText(context, txtBody.getMessage());
// 設置內容
holder.tv.setText(span, BufferType.SPANNABLE);
// 設置長按事件監聽
holder.tv.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
activity.startActivityForResult((new Intent(activity, ContextMenu.class)).putExtra("position", position).putExtra("type", EMMessage.Type.TXT.ordinal()), ChatActivity.REQUEST_CODE_CONTEXT_MENU);
return true;
}
});
if (message.direct == EMMessage.Direct.SEND) {
switch (message.status) {
case SUCCESS: // 發送成功
holder.pb.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.GONE);
break;
case FAIL: // 發送失敗
holder.pb.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.VISIBLE);
break;
case INPROGRESS: // 發送中
holder.pb.setVisibility(View.VISIBLE);
holder.staus_iv.setVisibility(View.GONE);
break;
default:
// 發送消息
sendMsgInBackground(message, holder);
}
}
}
其中對發送的文本消息進行狀態監聽。
/**
* 音視頻通話記錄
*
* @param message
* @param holder
* @param position
*/
private void handleCallMessage(EMMessage message, ViewHolder holder, final int position) {
TextMessageBody txtBody = (TextMessageBody) message.getBody();
holder.tv.setText(txtBody.getMessage());
}
當音視頻通話的時候不能顯示音視頻,所以將文本信息顯示出來。
/**
* 圖片消息
*
* @param message
* @param holder
* @param position
* @param convertView
*/
private void handleImageMessage(final EMMessage message, final ViewHolder holder, final int position, View convertView) {
//給當前圖片設置1個tag避免多張圖片躥亂
holder.pb.setTag(position);
holder.iv.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//長按設置事件
activity.startActivityForResult((new Intent(activity, ContextMenu.class)).putExtra("position", position).putExtra("type", EMMessage.Type.IMAGE.ordinal()), ChatActivity.REQUEST_CODE_CONTEXT_MENU);
return true;
}
});
// 接收方向的消息
if (message.direct == EMMessage.Direct.RECEIVE) {
// "it is receive msg";
if (message.status == EMMessage.Status.INPROGRESS) {
// "!!!! back receive";正在接收的時候顯示默許圖片
holder.iv.setImageResource(R.drawable.default_image);
//顯示下載進度條
showDownloadImageProgress(message, holder);
// downloadImage(message, holder);
} else {
// "!!!! not back receive, show image directly");
//發送圖片
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
holder.iv.setImageResource(R.drawable.default_image);
ImageMessageBody imgBody = (ImageMessageBody) message.getBody();
if (imgBody.getLocalUrl() != null) {
// String filePath = imgBody.getLocalUrl();
String remotePath = imgBody.getRemoteUrl();
String filePath = ImageUtils.getImagePath(remotePath);
String thumbRemoteUrl = imgBody.getThumbnailUrl();
String thumbnailPath = ImageUtils.getThumbnailImagePath(thumbRemoteUrl);
//將圖片加載到Imageview里面
showImageView(thumbnailPath, holder.iv, filePath, imgBody.getRemoteUrl(), message);
}
}
return;
}
// 發送的消息
// process send message
// send pic, show the pic directly
ImageMessageBody imgBody = (ImageMessageBody) message.getBody();
String filePath = imgBody.getLocalUrl();
if (filePath != null && new File(filePath).exists()) {
showImageView(ImageUtils.getThumbnailImagePath(filePath), holder.iv, filePath, null, message);
} else {
showImageView(ImageUtils.getThumbnailImagePath(filePath), holder.iv, filePath, IMAGE_DIR, message);
}
switch (message.status) {
//圖片加載狀態
case SUCCESS:
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.GONE);
break;
case FAIL:
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.VISIBLE);
break;
case INPROGRESS:
holder.staus_iv.setVisibility(View.GONE);
holder.pb.setVisibility(View.VISIBLE);
holder.tv.setVisibility(View.VISIBLE);
if (timers.containsKey(message.getMsgId()))
return;
// set a timer 設置1個定時器來顯示圖片的進度
final Timer timer = new Timer();
timers.put(message.getMsgId(), timer);
timer.schedule(new TimerTask() {
@Override
public void run() {
activity.runOnUiThread(new Runnable() {
public void run() {
holder.pb.setVisibility(View.VISIBLE);
holder.tv.setVisibility(View.VISIBLE);
holder.tv.setText(message.progress + "%");
if (message.status == EMMessage.Status.SUCCESS) {
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
// message.setSendingStatus(Message.SENDING_STATUS_SUCCESS);
timer.cancel();
} else if (message.status == EMMessage.Status.FAIL) {
//發送失敗
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
// message.setSendingStatus(Message.SENDING_STATUS_FAIL);
// message.setProgress(0);
holder.staus_iv.setVisibility(View.VISIBLE);
Toast.makeText(activity, activity.getString(R.string.send_fail) + activity.getString(R.string.connect_failuer_toast), 0).show();
timer.cancel();
}
}
});
}
}, 0, 500);
break;
default:
sendPictureMessage(message, holder);
}
}
圖片消息。
/**
* 視頻消息
*
* @param message
* @param holder
* @param position
* @param convertView
*/
private void handleVideoMessage(final EMMessage message, final ViewHolder holder, final int position, View convertView) {
//獲得視頻對象
VideoMessageBody videoBody = (VideoMessageBody) message.getBody();
// final File image=new File(PathUtil.getInstance().getVideoPath(),
// videoBody.getFileName());
String localThumb = videoBody.getLocalThumb();
holder.iv.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//長按菜單
activity.startActivityForResult(new Intent(activity, ContextMenu.class).putExtra("position", position).putExtra("type", EMMessage.Type.VIDEO.ordinal()), ChatActivity.REQUEST_CODE_CONTEXT_MENU);
return true;
}
});
if (localThumb != null) {
//展現視頻縮略圖
showVideoThumbView(localThumb, holder.iv, videoBody.getThumbnailUrl(), message);
}
if (videoBody.getLength() > 0) {
//設置視頻時長
String time = DateUtils.toTimeBySecond(videoBody.getLength());
holder.timeLength.setText(time);
}
//播放按鈕
holder.playBtn.setImageResource(R.drawable.video_download_btn_nor);
if (message.direct == EMMessage.Direct.RECEIVE) {
//接收到的視頻
if (videoBody.getVideoFileLength() > 0) {
//視頻大小
String size = TextFormater.getDataSize(videoBody.getVideoFileLength());
holder.size.setText(size);
}
} else {
//發送的視頻
if (videoBody.getLocalUrl() != null && new File(videoBody.getLocalUrl()).exists()) {
String size = TextFormater.getDataSize(new File(videoBody.getLocalUrl()).length());
holder.size.setText(size);
}
}
if (message.direct == EMMessage.Direct.RECEIVE) {
// System.err.println("it is receive msg");
//顯示進度條
if (message.status == EMMessage.Status.INPROGRESS) {
// System.err.println("!!!! back receive");
holder.iv.setImageResource(R.drawable.default_image);
showDownloadImageProgress(message, holder);
} else {
// System.err.println("!!!! not back receive, show image directly");
holder.iv.setImageResource(R.drawable.default_image);
if (localThumb != null) {
showVideoThumbView(localThumb, holder.iv, videoBody.getThumbnailUrl(), message);
}
}
return;
}
//對進度條設置tag
holder.pb.setTag(position);
// until here ,deal with send video msg
//發送的結果
switch (message.status) {
case SUCCESS:
holder.pb.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
break;
case FAIL:
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.VISIBLE);
break;
case INPROGRESS:
if (timers.containsKey(message.getMsgId()))
return;
// set a timer
final Timer timer = new Timer();
timers.put(message.getMsgId(), timer);
timer.schedule(new TimerTask() {
@Override
public void run() {
//500毫秒更新1次
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
holder.pb.setVisibility(View.VISIBLE);
holder.tv.setVisibility(View.VISIBLE);
holder.tv.setText(message.progress + "%");
if (message.status == EMMessage.Status.SUCCESS) {
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
// message.setSendingStatus(Message.SENDING_STATUS_SUCCESS);
timer.cancel();
} else if (message.status == EMMessage.Status.FAIL) {
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
// message.setSendingStatus(Message.SENDING_STATUS_FAIL);
// message.setProgress(0);
holder.staus_iv.setVisibility(View.VISIBLE);
Toast.makeText(activity, activity.getString(R.string.send_fail) + activity.getString(R.string.connect_failuer_toast), 0).show();
timer.cancel();
}
}
});
}
}, 0, 500);
break;
default:
// sendMsgInBackground(message, holder);
sendPictureMessage(message, holder);
}
}
視頻消息。<span style="font-size:18px;"> /**
* 語音消息
*
* @param message
* @param holder
* @param position
* @param convertView
*/
private void handleVoiceMessage(final EMMessage message, final ViewHolder holder, final int position, View convertView) {
//語音對象
VoiceMessageBody voiceBody = (VoiceMessageBody) message.getBody();
holder.tv.setText(voiceBody.getLength() + """);
//語音播放事件
holder.iv.setOnClickListener(new VoicePlayClickListener(message, holder.iv, holder.iv_read_status, this, activity, username));
holder.iv.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//長按上下文菜單
activity.startActivityForResult((new Intent(activity, ContextMenu.class)).putExtra("position", position).putExtra("type", EMMessage.Type.VOICE.ordinal()), ChatActivity.REQUEST_CODE_CONTEXT_MENU);
return true;
}
});
if (((ChatActivity) activity).playMsgId != null && ((ChatActivity) activity).playMsgId.equals(message.getMsgId()) && VoicePlayClickListener.isPlaying) {
AnimationDrawable voiceAnimation;
//顯示聲音播放動畫
if (message.direct == EMMessage.Direct.RECEIVE) {
holder.iv.setImageResource(R.anim.voice_from_icon);
} else {
holder.iv.setImageResource(R.anim.voice_to_icon);
}
voiceAnimation = (AnimationDrawable) holder.iv.getDrawable();
voiceAnimation.start();
} else {
//顯示為播放狀態下的界面
if (message.direct == EMMessage.Direct.RECEIVE) {
holder.iv.setImageResource(R.drawable.chatfrom_voice_playing);
} else {
holder.iv.setImageResource(R.drawable.chatto_voice_playing);
}
}
if (message.direct == EMMessage.Direct.RECEIVE) {
if (message.isListened()) {
// 隱藏語音未聽標志
holder.iv_read_status.setVisibility(View.INVISIBLE);
} else {
holder.iv_read_status.setVisibility(View.VISIBLE);
}
System.err.println("it is receive msg");
if (message.status == EMMessage.Status.INPROGRESS) {
holder.pb.setVisibility(View.VISIBLE);
System.err.println("!!!! back receive");
//監聽收到的語音文件消息完成下載
((FileMessageBody) message.getBody()).setDownloadCallback(new EMCallBack() {
@Override
public void onSuccess() {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
//下載以后更新數據
holder.pb.setVisibility(View.INVISIBLE);
notifyDataSetChanged();
}
});
}
@Override
public void onProgress(int progress, String status) {
}
@Override
public void onError(int code, String message) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
//下載失敗,隱藏進度條
holder.pb.setVisibility(View.INVISIBLE);
}
});
}
});
} else {
//沒有進度的情況
holder.pb.setVisibility(View.INVISIBLE);
}
return;
}
// until here, deal with send voice msg
//消息的結果
switch (message.status) {
case SUCCESS:
holder.pb.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.GONE);
break;
case FAIL:
holder.pb.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.VISIBLE);
break;
case INPROGRESS:
holder.pb.setVisibility(View.VISIBLE);
holder.staus_iv.setVisibility(View.GONE);
break;
default:
sendMsgInBackground(message, holder);
}
}</span>
語音消息。/**
* 文件消息
*
* @param message
* @param holder
* @param position
* @param convertView
*/
private void handleFileMessage(final EMMessage message, final ViewHolder holder, int position, View convertView) {
final NormalFileMessageBody fileMessageBody = (NormalFileMessageBody) message.getBody();
final String filePath = fileMessageBody.getLocalUrl();
holder.tv_file_name.setText(fileMessageBody.getFileName());
holder.tv_file_size.setText(TextFormater.getDataSize(fileMessageBody.getFileSize()));
holder.ll_container.setOnClickListener(new OnClickListener() {
//文件點擊事件
@Override
public void onClick(View view) {
File file = new File(filePath);
if (file != null && file.exists()) {
// 文件存在,直接打開(SDK所提供的類)
FileUtils.openFile(file, (Activity) context);
} else {
// 下載
context.startActivity(new Intent(context, ShowNormalFileActivity.class).putExtra("msgbody", fileMessageBody));
}
if (message.direct == EMMessage.Direct.RECEIVE && !message.isAcked) {
try {
//文件確認
EMChatManager.getInstance().ackMessageRead(message.getFrom(), message.getMsgId());
message.isAcked = true;
} catch (EaseMobException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
String st1 = context.getResources().getString(R.string.Have_downloaded);
String st2 = context.getResources().getString(R.string.Did_not_download);
if (message.direct == EMMessage.Direct.RECEIVE) { // 接收的消息
System.err.println("it is receive msg");
File file = new File(filePath);
if (file != null && file.exists()) {
holder.tv_file_download_state.setText(st1);
} else {
holder.tv_file_download_state.setText(st2);
}
return;
}
// until here, deal with send voice msg
switch (message.status) {
case SUCCESS:
holder.pb.setVisibility(View.INVISIBLE);
holder.tv.setVisibility(View.INVISIBLE);
holder.staus_iv.setVisibility(View.INVISIBLE);
break;
case FAIL:
holder.pb.setVisibility(View.INVISIBLE);
holder.tv.setVisibility(View.INVISIBLE);
holder.staus_iv.setVisibility(View.VISIBLE);
break;
case INPROGRESS:
if (timers.containsKey(message.getMsgId()))
return;
// set a timer
final Timer timer = new Timer();
timers.put(message.getMsgId(), timer);
timer.schedule(new TimerTask() {
@Override
public void run() {
activity.runOnUiThread(new Runnable() {
//與語音消息1樣的處理
@Override
public void run() {
holder.pb.setVisibility(View.VISIBLE);
holder.tv.setVisibility(View.VISIBLE);
holder.tv.setText(message.progress + "%");
if (message.status == EMMessage.Status.SUCCESS) {
holder.pb.setVisibility(View.INVISIBLE);
holder.tv.setVisibility(View.INVISIBLE);
timer.cancel();
} else if (message.status == EMMessage.Status.FAIL) {
holder.pb.setVisibility(View.INVISIBLE);
holder.tv.setVisibility(View.INVISIBLE);
holder.staus_iv.setVisibility(View.VISIBLE);
Toast.makeText(activity, activity.getString(R.string.send_fail) + activity.getString(R.string.connect_failuer_toast), 0).show();
timer.cancel();
}
}
});
}
}, 0, 500);
break;
default:
// 發送消息
sendMsgInBackground(message, holder);
}
}
文件消息。/**
* 處理位置消息
*
* @param message
* @param holder
* @param position
* @param convertView
*/
private void handleLocationMessage(final EMMessage message, final ViewHolder holder, final int position, View convertView) {
//位置信息對象
TextView locationView = ((TextView) convertView.findViewById(R.id.tv_location));
LocationMessageBody locBody = (LocationMessageBody) message.getBody();
locationView.setText(locBody.getAddress());
//經緯度信息
LatLng loc = new LatLng(locBody.getLatitude(), locBody.getLongitude());
//地圖點擊事假
locationView.setOnClickListener(new MapClickListener(loc, locBody.getAddress()));
locationView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
//長按 上下文菜單
activity.startActivityForResult((new Intent(activity, ContextMenu.class)).putExtra("position", position).putExtra("type", EMMessage.Type.LOCATION.ordinal()), ChatActivity.REQUEST_CODE_CONTEXT_MENU);
return false;
}
});
if (message.direct == EMMessage.Direct.RECEIVE) {
return;
}
// deal with send message
//消息發送狀態
switch (message.status) {
case SUCCESS:
holder.pb.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.GONE);
break;
case FAIL:
holder.pb.setVisibility(View.GONE);
holder.staus_iv.setVisibility(View.VISIBLE);
break;
case INPROGRESS:
holder.pb.setVisibility(View.VISIBLE);
break;
default:
sendMsgInBackground(message, holder);
}
}
位置消息。
以上都為消息的邏輯處理,接下來是發送的處理。
/**
* 發送消息
*
* @param message
* @param holder<pre name="code" class="java"> /*
* 文件下載
* chat sdk will automatic download thumbnail image for the image message we
* need to register callback show the download progress
*/
private void showDownloadImageProgress(final EMMessage message, final ViewHolder holder) {
System.err.println("!!! show download image progress");
// final ImageMessageBody msgbody = (ImageMessageBody)
// message.getBody();
final FileMessageBody msgbody = (FileMessageBody) message.getBody();
if (holder.pb != null)
holder.pb.setVisibility(View.VISIBLE);
if (holder.tv != null)
holder.tv.setVisibility(View.VISIBLE);
// 異步下載文件
msgbody.setDownloadCallback(new EMCallBack() {
@Override
public void onSuccess() {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
// message.setBackReceive(false);
if (message.getType() == EMMessage.Type.IMAGE) {
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
}
notifyDataSetChanged();
}
});
}
@Override
public void onError(int code, String message) {
}
@Override
public void onProgress(final int progress, String status) {
if (message.getType() == EMMessage.Type.IMAGE) {
activity.runOnUiThread(new Runnable() {
//顯示下載進度
@Override
public void run() {
holder.tv.setText(progress + "%");
}
});
}
}
});
}
* @param position */public void sendMsgInBackground(final EMMessage message, final ViewHolder holder) {holder.staus_iv.setVisibility(View.GONE);holder.pb.setVisibility(View.VISIBLE);final long start = System.currentTimeMillis();// 調用sdk發送異步發送方法EMChatManager.getInstance().sendMessage(message,
new EMCallBack() {@Overridepublic void onSuccess() {//更新發送狀態updateSendedView(message, holder);}@Overridepublic void onError(int code, String error) {updateSendedView(message, holder);}@Overridepublic void onProgress(int progress, String status) {}});}
/*
* 發送圖片 send message with new sdk
*/
private void sendPictureMessage(final EMMessage message, final ViewHolder holder) {
try {
// 獲得發送對象
String to = message.getTo();
// before send, update ui
holder.staus_iv.setVisibility(View.GONE);
holder.pb.setVisibility(View.VISIBLE);
holder.tv.setVisibility(View.VISIBLE);
holder.tv.setText("0%");
final long start = System.currentTimeMillis();
// if (chatType == ChatActivity.CHATTYPE_SINGLE) {
EMChatManager.getInstance().sendMessage(message, new EMCallBack() {
// 異步發送
@Override
public void onSuccess() {
Log.d(TAG, "send image message successfully");
activity.runOnUiThread(new Runnable() {
public void run() {
// send success
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
}
});
}
@Override
public void onError(int code, String error) {
activity.runOnUiThread(new Runnable() {
public void run() {
holder.pb.setVisibility(View.GONE);
holder.tv.setVisibility(View.GONE);
// message.setSendingStatus(Message.SENDING_STATUS_FAIL);
holder.staus_iv.setVisibility(View.VISIBLE);
Toast.makeText(activity, activity.getString(R.string.send_fail) + activity.getString(R.string.connect_failuer_toast), 0).show();
}
});
}
@Override
public void onProgress(final int progress, String status) {
activity.runOnUiThread(new Runnable() {
public void run() {
holder.tv.setText(progress + "%");
}
});
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 更新ui上消息發送狀態
*
* @param message
* @param holder
*/
private void updateSendedView(final EMMessage message, final ViewHolder holder) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
// send success
if (message.getType() == EMMessage.Type.VIDEO) {
holder.tv.setVisibility(View.GONE);
}
System.out.println("message status : " + message.status);
if (message.status == EMMessage.Status.SUCCESS) {
// if (message.getType() == EMMessage.Type.FILE) {
// holder.pb.setVisibility(View.INVISIBLE);
// holder.staus_iv.setVisibility(View.INVISIBLE);
// } else {
// holder.pb.setVisibility(View.GONE);
// holder.staus_iv.setVisibility(View.GONE);
// }
} else if (message.status == EMMessage.Status.FAIL) {
// if (message.getType() == EMMessage.Type.FILE) {
// holder.pb.setVisibility(View.INVISIBLE);
// } else {
// holder.pb.setVisibility(View.GONE);
// }
// holder.staus_iv.setVisibility(View.VISIBLE);
Toast.makeText(activity, activity.getString(R.string.send_fail) + activity.getString(R.string.connect_failuer_toast), 0).show();
}
notifyDataSetChanged();
}
});
}
/**
* load image into image view
* 顯示圖片到控件中
* @param thumbernailPath
* @param iv
* @param position
* @return the image exists or not
*/
private boolean showImageView(final String thumbernailPath, final ImageView iv, final String localFullSizePath, String remoteDir, final EMMessage message) {
// String imagename =
// localFullSizePath.substring(localFullSizePath.lastIndexOf("/") + 1,
// localFullSizePath.length());
// final String remote = remoteDir != null ? remoteDir+imagename :
// imagename;
final String remote = remoteDir;
EMLog.d("###", "local = " + localFullSizePath + " remote: " + remote);
// first check if the thumbnail image already loaded into cache
//獲得緩存文件
Bitmap bitmap = ImageCache.getInstance().get(thumbernailPath);
if (bitmap != null) {
//文件存在
// thumbnail image is already loaded, reuse the drawable
iv.setImageBitmap(bitmap);
iv.setClickable(true);
iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.err.println("image view on click");
//顯示大圖界面
Intent intent = new Intent(activity, ShowBigImage.class);
File file = new File(localFullSizePath);
if (file.exists()) {
Uri uri = Uri.fromFile(file);
intent.putExtra("uri", uri);
System.err.println("here need to check why download everytime");
} else {
// The local full size pic does not exist yet.
// ShowBigImage needs to download it from the server
// first
// intent.putExtra("", message.get);
ImageMessageBody body = (ImageMessageBody) message.getBody();
intent.putExtra("secret", body.getSecret());
intent.putExtra("remotepath", remote);
}
if (message != null && message.direct == EMMessage.Direct.RECEIVE && !message.isAcked && message.getChatType() != ChatType.GroupChat) {
try {
EMChatManager.getInstance().ackMessageRead(message.getFrom(), message.getMsgId());
message.isAcked = true;
} catch (Exception e) {
e.printStackTrace();
}
}
activity.startActivity(intent);
}
});
return true;
} else {
//文件不存在 重新加載
new LoadImageTask().execute(thumbernailPath, localFullSizePath, remote, message.getChatType(), iv, activity, message);
return true;
}
}
/**
* 展現視頻縮略圖
*
* @param localThumb
* 本地縮略圖路徑
* @param iv
* @param thumbnailUrl
* 遠程縮略圖路徑
* @param message
*/
private void showVideoThumbView(String localThumb, ImageView iv, String thumbnailUrl, final EMMessage message) {
// first check if the thumbnail image already loaded into cache
Bitmap bitmap = ImageCache.getInstance().get(localThumb);
if (bitmap != null) {
// thumbnail image is already loaded, reuse the drawable
iv.setImageBitmap(bitmap);
iv.setClickable(true);
iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
VideoMessageBody videoBody = (VideoMessageBody) message.getBody();
System.err.println("video view is on click");
Intent intent = new Intent(activity, ShowVideoActivity.class);
intent.putExtra("localpath", videoBody.getLocalUrl());
intent.putExtra("secret", videoBody.getSecret());
intent.putExtra("remotepath", videoBody.getRemoteUrl());
if (message != null && message.direct == EMMessage.Direct.RECEIVE && !message.isAcked && message.getChatType() != ChatType.GroupChat) {
message.isAcked = true;
try {
EMChatManager.getInstance().ackMessageRead(message.getFrom(), message.getMsgId());
} catch (Exception e) {
e.printStackTrace();
}
}
activity.startActivity(intent);
}
});
} else {
new LoadVideoImageTask().execute(localThumb, thumbnailUrl, iv, activity, message, this);
}
}
/*
* 點擊地圖消息listener
*/
class MapClickListener implements View.OnClickListener {
LatLng location;
String address;
public MapClickListener(LatLng loc, String address) {
location = loc;
this.address = address;
}
@Override
public void onClick(View v) {
Intent intent;
//將聊天界面上的地圖用地圖界面顯示出來
intent = new Intent(context, BaiduMapActivity.class);
intent.putExtra("latitude", location.latitude);
intent.putExtra("longitude", location.longitude);
intent.putExtra("address", address);
activity.startActivity(intent);
}
}
至此,顯示聊天內容大體完成了,其中還有部份未詳講,顯示大圖界面,地圖界面。此處不在詳細說明。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈