即时聊天APP(五) - 聊天界面

设置界面没什么好说的,无非也就是加了个对话框来二次提醒用户,现在来讲讲聊天界面。

聊天界面初始化时会得到一个参数,就是对方的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();
}

即时聊天APP(五) - 聊天界面

上一篇:pytest文档25-conftest.py作用范围


下一篇:即时聊天APP(三) - 注册和登陆