設置界面沒什麼好說的,無非也就是加了個對話框來二次提醒用戶,如今來說講聊天界面。
聊天界面初始化時會獲得一個參數,就是對方的id,並設置在標題欄的位置,此界面也是使用RecyclerView來展現聊天消息。
首先爲RecyclerView添加布局管理器(線性佈局),而且爲其添加適配器,寫適配器以前先寫類,消息類展現:
public class Msg extends LitePalSupport {
public static final int TYPE_RECEIVED = 0; // 接收消息
public static final int TYPE_SENT = 1; // 發送消息
private String Sender;
private String Receiver;
private String content;
private int type;
Msg(String content, int type) {
this.content = content;
this.type = type;
}
public static int getTypeReceived() {
return TYPE_RECEIVED;
}
public static int getTypeSent() {
return TYPE_SENT;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getSender() {
return Sender;
}
public void setSender(String sender) {
Sender = sender;
}
public String getReceiver() {
return Receiver;
}
public void setReceiver(String receiver) {
Receiver = receiver;
}
}
而後寫適配器,用於RecyclerView的展現以及各類事件的處理,首先定義一個內部類ViewHolder,繼承自RecyclerView.ViewHolder,用來緩存子項的各個實例,提升效率,其他的我都用註釋進行標註了:
public class MsgAdapter extends RecyclerView.Adapter{
private ListmMsgList;
static class ViewHolder extends RecyclerView.ViewHolder {
LinearLayout leftLayout;
LinearLayout rightLayout;
TextView leftMsg;
TextView rightMsg;
// view表示父類的佈局,用其獲取子項
ViewHolder(View view) {
super(view);
leftLayout = view.findViewById(R.id.left_layout);
rightLayout = view.findViewById(R.id.right_layout);
leftMsg = view.findViewById(R.id.left_msg);
rightMsg = view.findViewById(R.id.right_msg);
}
}
MsgAdapter(ListmsgList) {
mMsgList = msgList;
}
/**
* 建立 ViewHolder 加載 RecycleView 子項的佈局
* @param parent
* @param viewType
* @return
*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item, parent, false);
return new ViewHolder(view);
}
/**
* 爲 RecycleView 子項賦值
* 賦值經過 position 判斷子項位置
* 當子項進入界面時執行
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Msg msg = mMsgList.get(position);
if (msg.getType() == Msg.TYPE_RECEIVED) {
// 若是是收到的消息,則顯示左邊的消息佈局,將右邊的消息佈局隱藏
holder.leftLayout.setVisibility(View.VISIBLE);
holder.rightLayout.setVisibility(View.GONE);
holder.leftMsg.setText(msg.getContent());
} else if (msg.getType() == Msg.TYPE_SENT) {
// 若是是發出的消息,則顯示右邊的消息佈局,將左邊的消息佈局隱藏
holder.rightLayout.setVisibility(View.VISIBLE);
holder.leftLayout.setVisibility(View.GONE);
holder.rightMsg.setText(msg.getContent());
}
}
//返回子項個數
@Override
public int getItemCount() {
return mMsgList.size();
}
}
RecyclerView介紹完以後,返回來繼續介紹聊天界面,初始化的時候也是先讀取數據庫,這裏我作了限制,只查詢出最近的50條聊天記錄:
//讀取數據庫
private void read__db() {
msgList.clear();
msgL = LitePal.where("Sender = ? and Receiver = ?;",username,friend).find(Msg.class);
int count = msgL.size();
//判斷消息長度,最多從數據庫讀取50條消息
if(count > 0 && count <=50 ){
sel_50(0);
}else if(count > 50){
sel_50(count - 50);
}
// 當有新消息時,刷新ListView中的顯示
adapter.notifyItemInserted(msgList.size() - 1);
// 將ListView定位到最後一行
msgRecyclerView.scrollToPosition(msgList.size() - 1);
}
//查詢截取50條數據
private void sel_50(int i){
for (; i < msgL.size(); i++){
//加個異常
try{
Msg msgLi = new Msg(msgL.get(i).getContent(),msgL.get(i).getType());
msgList.add(msgLi);
}catch (Exception e) {}
}
}
初始化完畢,當用戶點擊發送按鈕的時候使用BmobIMConversation的sendMessage方法進行發送消息(具體請參考官方文檔):
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//檢查網絡鏈接
if(!NetWork.isNetConnection(Main.this))
Toast.makeText(Main.this,"無網絡鏈接!",Toast.LENGTH_SHORT).show();
else{
if(!MainActivity.isConnect)
Toast.makeText(Main.this,"鏈接服務器失敗!",Toast.LENGTH_SHORT).show();
//網絡正常
String content = inputText.getText().toString();
if (!"".equals(content)) {
final Msg ms = new Msg(content, Msg.TYPE_SENT);
//鏈接成功,發送消息
BmobIMUserInfo info =new BmobIMUserInfo();
info.setAvatar("填寫接收者的頭像");
info.setUserId(friend);
info.setName("填寫接收者的名字");
ms.setReceiver(friend);
ms.setSender(MyUser.getUni());
Tips.Receiver = friend;
// BmobIMConversation conversationEntrance =
try{
BmobIM.getInstance().startPrivateConversation(info, new ConversationListener() {
@Override
public void done(BmobIMConversation c, BmobException e) {
if(e==null){
//在此跳轉到聊天頁面或者直接轉化
mBmobIMConversation=BmobIMConversation.obtain(BmobIMClient.getInstance(),c);
BmobIMTextMessage msg =new BmobIMTextMessage();
msg.setContent(ms.getContent());
//發送消息
mBmobIMConversation.sendMessage(msg, new MessageSendListener() {
@Override
public void done(BmobIMMessage msg, BmobException e) {
if (e != null) {
Toast.makeText(Main.this, "發送失敗", Toast.LENGTH_SHORT).show();
}else{
//添加消息
add(ms);
}
}
});
}else{
Toast.makeText(Main.this, "開啓會話出錯", Toast.LENGTH_SHORT).show();
}
}
});
}catch (Exception e){}
}
}
}
});
消息發送成功以後要進行本地數據庫的更新,不光要更新消息列表,也要更新會話列表,使會話列表展現的是最新的消息:
//添加消息
public static void add(Msg msg){
if(msg.getType() == 1){
msgList.add(msg);
// 當有新消息時,刷新ListView中的顯示
adapter.notifyItemInserted(msgList.size() - 1);
// 將ListView定位到最後一行
msgRecyclerView.scrollToPosition(msgList.size() - 1);
// 清空輸入框中的內容
inputText.setText("");
}else if(msg.getReceiver().equals(friend)) {
msgList.add(msg);
adapter.notifyItemInserted(msgList.size() - 1);
msgRecyclerView.scrollToPosition(msgList.size() - 1);
}
//保存數據庫
msg.save();
int len = msg.getContent().length();
ConList lis;
if(len > 15){
String show = msg.getContent().substring(0,12);
if(msg.getType() == 1)
lis = new ConList(friend,"我:"+show+"......");
else
lis = new ConList(friend,"對方:"+show+"......");
}else {
if(msg.getType() == 1)
lis = new ConList(friend,"我:"+msg.getContent());
else
lis = new ConList(friend,"對方:"+msg.getContent());
}
lis.save();
}