在会话界面中,主要是对会话记录的操作。就跟QQ上面的一样,最左边的一个Tab。管理会话历史,并动态显示消息数量。
因为整个会话界面是由Fragment所组成,所以没有清单文件。接下来咱们先来看看布局文件的构成。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/common_bg"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/height_top_bar"
android:background="@color/top_bar_normal_bg"
android:gravity="center_vertical" >
<TextView
android:id="@+id/message_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/session"
android:textColor="#fff"
android:textSize="18sp" />
</RelativeLayout>
<include layout="@layout/search_bar" />
<include
android:id="@+id/rl_error_item"
layout="@layout/chat_neterror_item"
android:visibility="gone" />
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:cacheColorHint="#00000000"
android:divider="@null" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:background="#ededed"
android:paddingLeft="@dimen/padding_search_bar"
android:paddingRight="@dimen/padding_search_bar" >
<EditText
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingLeft="5dp"
android:id="@+id/query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:background="@drawable/seabar_input"
android:drawableLeft="@drawable/search_bar_icon_normal"
android:focusable="true"
android:focusableInTouchMode="true"
android:textColorHint="#b3b3b3"
android:textSize="16sp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:singleLine="true"/>
<ImageButton
android:id="@+id/search_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="3dp"
android:background="@android:color/transparent"
android:padding="6dp"
android:src="@drawable/search_clear"
android:visibility="invisible" />
</RelativeLayout>
可以简单,最顶端是一个Title,接下来是一个自定义的搜索栏,还有一个错误提示栏,不过默认状况下是不显示的,最下面就是这个界面最重要的组成了------ListView。
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null && savedInstanceState.getBoolean("isConflict", false))
return;
inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
errorItem = (RelativeLayout) getView().findViewById(R.id.rl_error_item);
errorText = (TextView) errorItem.findViewById(R.id.tv_connect_errormsg);
// 添加会话列表
conversationList.addAll(loadConversationsWithRecentChat());
listView = (ListView) getView().findViewById(R.id.list);
adapter = new ChatAllHistoryAdapter(getActivity(), 1, conversationList);
// 设置adapter
listView.setAdapter(adapter);
final String st2 = getResources().getString(R.string.Cant_chat_with_yourself);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
EMConversation conversation = adapter.getItem(position);
String username = conversation.getUserName();
if (username.equals(DemoApplication.getInstance().getUserName()))
Toast.makeText(getActivity(), st2, 0).show();
else {
// 进入聊天页面
Intent intent = new Intent(getActivity(), ChatActivity.class);
if (conversation.isGroup()) {
// it is group chat
intent.putExtra("chatType", ChatActivity.CHATTYPE_GROUP);
intent.putExtra("groupId", username);
} else {
// it is single chat
intent.putExtra("userId", username);
}
startActivity(intent);
}
}
});
// 注册上下文菜单
registerForContextMenu(listView);
listView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 隐藏软键盘
hideSoftKeyboard();
return false;
}
});
// 搜索框
query = (EditText) getView().findViewById(R.id.query);
String strSearch = getResources().getString(R.string.search);
query.setHint(strSearch);
// 搜索框中清除button
clearSearch = (ImageButton) getView().findViewById(R.id.search_clear);
query.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s);
if (s.length() > 0) {
clearSearch.setVisibility(View.VISIBLE);
} else {
clearSearch.setVisibility(View.INVISIBLE);
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void afterTextChanged(Editable s) {
}
});
clearSearch.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
query.getText().clear();
hideSoftKeyboard();
}
});
}
// 隐藏软键盘
void hideSoftKeyboard() {
if (getActivity().getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
if (getActivity().getCurrentFocus() != null)
inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
在onActivityCreated方法中,最界面的逻辑处理以及数据的初始化过程,先从SDK提供的方法获取会话,然后显示出来,并且设置相应的项目点击事件。以及查询和软键盘的相应处理。
其中对会话列表还设置了上下文菜单,可以对选择的某条会话进行删除操作。
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
// if(((AdapterContextMenuInfo)menuInfo).position > 0){ m,
getActivity().getMenuInflater().inflate(R.menu.delete_message, menu);
// }
}
@Override
public boolean onContextItemSelected(MenuItem item) {
boolean handled = false;
boolean deleteMessage = false;
if (item.getItemId() == R.id.delete_message) {
deleteMessage = true;
handled = true;
} else if (item.getItemId() == R.id.delete_conversation) {
deleteMessage = false;
handled = true;
}
EMConversation tobeDeleteCons = adapter.getItem(((AdapterContextMenuInfo) item.getMenuInfo()).position);
// 删除此会话
EMChatManager.getInstance().deleteConversation(tobeDeleteCons.getUserName(), tobeDeleteCons.isGroup(), deleteMessage);
InviteMessgeDao inviteMessgeDao = new InviteMessgeDao(getActivity());
inviteMessgeDao.deleteMessage(tobeDeleteCons.getUserName());
adapter.remove(tobeDeleteCons);
adapter.notifyDataSetChanged();
// 更新消息未读数
((MainActivity) getActivity()).updateUnreadLabel();
return handled ? true : super.onContextItemSelected(item);
}
当删除会话后调用Main中的updateUnreadLabel更新未读消息数。
/**
* 获取所有会话
*
* @param context
* @return +
*/
private List<EMConversation> loadConversationsWithRecentChat() {
// 获取所有会话,包括陌生人
Hashtable<String, EMConversation> conversations = EMChatManager.getInstance().getAllConversations();
// 过滤掉messages size为0的conversation
/**
* 如果在排序过程中有新消息收到,lastMsgTime会发生变化 影响排序过程,Collection.sort会产生异常
* 保证Conversation在Sort过程中最后一条消息的时间不变 避免并发问题
*/
List<Pair<Long, EMConversation>> sortList = new ArrayList<Pair<Long, EMConversation>>();
synchronized (conversations) {
for (EMConversation conversation : conversations.values()) {
if (conversation.getAllMessages().size() != 0) {
sortList.add(new Pair<Long, EMConversation>(conversation.getLastMessage().getMsgTime(), conversation));
}
}
}
try {
// Internal is TimSort algorithm, has bug
sortConversationByLastChatTime(sortList);
} catch (Exception e) {
e.printStackTrace();
}
List<EMConversation> list = new ArrayList<EMConversation>();
for (Pair<Long, EMConversation> sortItem : sortList) {
list.add(sortItem.second);
}
return list;
}
/**
* 根据最后一条消息的时间排序
*
* @param usernames
*/
private void sortConversationByLastChatTime(List<Pair<Long, EMConversation>> conversationList) {
Collections.sort(conversationList, new Comparator<Pair<Long, EMConversation>>() {
@Override
public int compare(final Pair<Long, EMConversation> con1, final Pair<Long, EMConversation> con2) {
if (con1.first == con2.first) {
return 0;
} else if (con2.first > con1.first) {
return 1;
} else {
return -1;
}
}
});
}
获得所有会话信息,并按照时间顺序进行排列。
//当点击MAIN界面中其他Tab的时候会隐藏当前Fragment,调用此方法,并且刷新界面
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
this.hidden = hidden;
if (!hidden) {
refresh();
}
}
//当重新显示,并且没有隐藏的话,刷新。
@Override
public void onResume() {
super.onResume();
if (!hidden && !((MainActivity) getActivity()).isConflict) {
refresh();
}
}
/**
* 刷新页面, 刷新的时候重新获取会话列表。
*/
public void refresh() {
conversationList.clear();
conversationList.addAll(loadConversationsWithRecentChat());
if (adapter != null)
adapter.notifyDataSetChanged();
}
在界面改变之后删除之前数据,重新显示。
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (((MainActivity) getActivity()).isConflict) {
outState.putBoolean("isConflict", true);
} else if (((MainActivity) getActivity()).getCurrentAccountRemoved()) {
outState.putBoolean(Constant.ACCOUNT_REMOVED, true);
}
}
保存账号信息。至此,会话列表就完成了,其中比较简单。