即时聊天APP - 聊天界面

【即时聊天APP - 聊天界面】少年乘勇气,百战过乌孙。这篇文章主要讲述即时聊天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(); }


    推荐阅读