Android即时通讯--仿QQ即时聊天:(五)聊天模块
2016-02-27 15:52
417 查看
1、复杂ListView的展示
聊天模块其实就是一个复杂的ListView,在数据适配器中,从application中获取到当前登录的用户,与聊天消息中的from参数进行比较,如果两者相同则说明是自己发送的消息,那么ListView中就显示发送消息的布局,否则显示接收消息的布局。适配器的代码如下:/** * 聊天消息的适配器 * * @author ZHY * */ public class ChartMessageAdapter extends ArrayAdapter<QQMessage> { ImApp app; public ChartMessageAdapter(Context context, List<QQMessage> objects) { super(context, 0, objects); Activity activity = (Activity) context; app = (ImApp) activity.getApplication(); } /** * 根据集合中的position位置,返回不同的值,代表不同的布局 0代表自己发送的消息 1代表接收到的消息 * */ @Override public int getItemViewType(int position) {// 这个方法是给getView用得 QQMessage msg = getItem(position); // 消息来自谁,如果消息来自我自己,说明是我发送的 if (msg.from == app.getMyAccount()) { // 我自己的消息,发送 return 0; } else { return 1; } } /** * 两种布局 */ @Override public int getViewTypeCount() { return 2; } class ViewHolder { TextView time; TextView content; ImageView head; } @Override public View getView(int position, View convertView, ViewGroup parent) { int type = getItemViewType(position); if (0 == type) { // 发送的布局 ViewHolder holder; if (convertView == null) { convertView = View.inflate(getContext(), R.layout.item_chat_send, null); holder = new ViewHolder(); holder.time = (TextView) convertView.findViewById(R.id.time); holder.content = (TextView) convertView .findViewById(R.id.content); holder.head = (ImageView) convertView.findViewById(R.id.head); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } // 设置值 QQMessage msg = getItem(position); holder.time.setText(msg.sendTime); holder.head.setImageResource(msg.fromAvatar); holder.content.setText(msg.content); return convertView; } else { // 接收的布局 ViewHolder holder; if (convertView == null) { convertView = View.inflate(getContext(), R.layout.item_chat_receive, null); holder = new ViewHolder(); holder.time = (TextView) convertView.findViewById(R.id.time); holder.content = (TextView) convertView .findViewById(R.id.content); holder.head = (ImageView) convertView.findViewById(R.id.head); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } // 设置值 QQMessage msg = getItem(position); holder.head.setImageResource(msg.fromAvatar); holder.time.setText(msg.sendTime); holder.content.setText(msg.content); return convertView; } } }
2、消息处理
在聊天页面中添加接收消息的监听,如果接收到的消息是聊天消息,那么就将接收到的消息添加到messages消息集合中,然后通知适配器数据发生了变化,进而刷新界面。当用户点击发送按钮的时候,封装消息,将消息发送个给服务器。聊天界面的代码如下:/** * 聊天界面 * * @author ZHY * */ public class ChartActivity extends Activity { @ViewInject(R.id.title) private TextView title; @ViewInject(R.id.listview) private ListView listView; @ViewInject(R.id.input) private EditText input; private ImApp app; private ChartMessageAdapter adapter; // 这是点击的用户,也就是你要发消息给谁 private String toNick;// 要发送给谁 private long toAccount;// y要发送的账号 private long fromAccount;// 我的账号,我要跟谁睡聊天 private String inputStr;// 聊天内容 // 聊天消息的集合 private List<QQMessage> messages = new ArrayList<QQMessage>(); // 点击发送按钮的时候,获得输入框中的内容,将内容封装到messages集合中,聊调消息是一个QQMessageJava对象,一定包含四个字段 @OnClick(R.id.send) public void send(View view) { // Toast.makeText(getBaseContext(), "ddadasf", 0).show(); inputStr = input.getText().toString().trim(); // 清空输入框 input.setText(""); final QQMessage msg = new QQMessage(); if ("".equals(inputStr)) { Toast.makeText(getApplicationContext(), "不能为空", 0).show(); return; } msg.type = QQMessageType.MSG_TYPE_CHAT_P2P; msg.from = fromAccount; msg.to = toAccount; msg.content = inputStr; msg.fromAvatar = R.drawable.ic_launcher; messages.add(msg); // 数据集合有了,创建适配器 // 刷新消息 if (adapter != null) { adapter.notifyDataSetChanged(); } // 展示到最新发送的消息处 if (messages.size() > 0) { listView.setSelection(messages.size() - 1); } // 发送消息到服务器--子线程 ThreadUtils.runInSubThread(new Runnable() { public void run() { try { app.getMyConn().sendMessage(msg); } catch (IOException e) { e.printStackTrace(); } } }); } /** * 接收消息,使用监听器 */ private OnMessageListener listener = new OnMessageListener() { public void onReveive(final QQMessage msg) { // 注意onReveive是子线程,更新界面一定要在主线程中 ThreadUtils.runInUiThread(new Runnable() { public void run() { // 服务器返回回来的消息 System.out.println(msg.content); if (QQMessageType.MSG_TYPE_CHAT_P2P.equals(msg.type)) { messages.add(msg);// 把消息加到消息集合中,这是最新的消息 // 刷新消息 if (adapter != null) { adapter.notifyDataSetChanged(); } // 展示到最新发送的消息出 if (messages.size() > 0) { listView.setSelection(messages.size() - 1); } } } }); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_chart); ViewUtils.inject(this);// 相当于findViewByID app = (ImApp) getApplication(); // 开启监听 app.getMyConn().addOnMessageListener(listener); // 聊天的界面是复杂的listView。发送消息的条目是item_chat_send.xml布局,接收到的消息现实的条目是item_chat_receive.xml布局 /** * 聊天的消息 content "约不?" type chatp2p from 老王 to 大头 */ // 获得从上一个界面获取的账号与昵称 Intent intent = getIntent(); toNick = intent.getStringExtra("nick"); toAccount = intent.getLongExtra("account", 0); title.setText("与" + toNick + "聊天中"); fromAccount = app.getMyAccount();// 我的账户 adapter = new ChartMessageAdapter(this, messages); listView.setAdapter(adapter); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); app.getMyConn().removeOnMessageListener(listener); } }至此,基于Socket的Android即时通讯软件就介绍完了,功能很丑陋,原理基本能说得通,自己留一份备忘,同时也希望能帮到别人。源码的话,稍后整理发出来,整个项目运行起来的效果如下。有待完善的地方还有很多,望不吝赐教,与君共勉,共同进步!!!
点我下载源码
相关文章推荐
- Android Activity 的四种启动模式 lunchMode 和 Intent.setFlags();
- android meta-data的使用以及含义
- android 【九种对话框】的实现方式
- 【Android动画】之Tween动画 (渐变、缩放、位移、旋转)
- PDF阅读器系列之--MuPDF源码分析过程(二)
- Android高手进阶:Adapter深入理解与优化
- Android Binder机制(超级详尽)
- android 仿nice实现在图片上打标签
- Android Fragment 生命周期图
- 学习android service记录
- Android数据通信——JSON&Gson(Android studio)
- Android View 事件体系1
- H5为主的Hybrid App技术方案的设想及设计-Android
- Android Studio 9 patch 编译错误
- android、IOS和手机基础知识
- Android_为什么要继承onMeasure()
- android 性能优化-电量篇
- BUG记录之Android开发
- android的 root权限
- ubuntu下安装AndroidStudio