学习android不久,想实现一个聊天功能,发现主要时间还是花在了聊天界面的布局上面。主要功能类似于一个聊天室。客户端启动后,发送的内容都通过socket传给服务端,服务端收到消息后,遍历socket列表中每一个socket,当然除掉消息来源的这个socket,然后发送该消息。

首先附上xml的代码

main.xml聊天的主界面


一个item的布局,就拿右边的对话框举例吧,右边的对话框多一个 android:gravity="right"

聊天界面的对话框是一个listview,但是listview的每一个item的布局取决于消息的来源

所以自定义一个adaptar,继承BaseAdapter,最重要的是getview的重写。我这里在获取内容的时候,就加上标志,根据标志判断用哪个布局。感觉总有点怪怪的。如果有好方法,还请大神指教。

package com.hitwhwlp.love;
import java.util.HashMap;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter {
private Context context;
private List> list;
public MyAdapter(Context context, List> listItems) {
// TODO Auto-generated constructor stubthis.context = context;
this.list = listItems;
this.context = context;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
// ViewHolder静态类
static class ViewHolder {
public TextView content;
}
// 重写getView
//这边写的。。。需要优化
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
// if (convertView == null) {
holder = new ViewHolder();
if ("0" == list.get(position).get("flag").toString()) {
convertView = LayoutInflater.from(context).inflate(
R.layout.left_item, null);
holder.content = (TextView) convertView.findViewById(R.id.content1);
} else {
convertView = LayoutInflater.from(context).inflate(
R.layout.right_item, null);
holder.content = (TextView) convertView.findViewById(R.id.content2);
}
// convertView.setTag(holder);
// } else {
// holder = (ViewHolder) convertView.getTag();
// }
holder.content.setText(list.get(position).get("content").toString());
return convertView;
}
}

准备工作做好了,上MainActivity啦

package com.hitwhwlp.love;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends Activity {
private ImageButton faceButton;
private EditText inputText;
private Button sendButton;
Handler handler;
ClientThread clientThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
inputText = (EditText) findViewById(R.id.input);
sendButton = (Button) findViewById(R.id.send);
inputText = (EditText) findViewById(R.id.input);
sendButton = (Button) findViewById(R.id.send);
final List> ListItems = new ArrayList>();
ListView list = (ListView) findViewById(R.id.list);
final MyAdapter adapter = new MyAdapter(MainActivity.this, ListItems);
list.setAdapter(adapter);
handler = new Handler()
{
@Override
public void handleMessage(Message msg) {
// 如果消息来自于子线程
if (msg.what == 0x123) {
// 将读取的内容追加显示在listview
HashMaptempListItems = new HashMap (); tempListItems.put("flag", "0"); tempListItems.put("content", msg.obj.toString()); ListItems.add(tempListItems); adapter.notifyDataSetChanged(); } } }; clientThread = new ClientThread(handler); // 客户端启动ClientThread线程创建网络连接、读取来自服务器的数据 new Thread(clientThread).start(); // ① sendButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub try { // 当用户按下发送按钮后,将用户输入的数据封装成Message, // 然后发送给子线程的Handler Message msg = new Message(); msg.what = 0x345; msg.obj = inputText.getText().toString(); clientThread.revHandler.sendMessage(msg); HashMap tempListItems = new HashMap (); tempListItems.put("flag", "1"); tempListItems.put("content",inputText.getText().toString() ); ListItems.add(tempListItems); adapter.notifyDataSetChanged(); // 清空input文本框 inputText.setText(""); } catch (Exception e) { e.printStackTrace(); } } }); } } 

当发送一个消息时,本地消息是直接加到listview中的,如果没有发送成功,但是已经显示了,是不是怪怪的?但其实如果没有发送成功,会检测到异常,直接到了下面的catch里根本不会执行,连清空输入框都没有执行。

至于如何接收来自服务端的消息,以及将发送的内容写到网络,上ClientThread(由于本人才结束大一的生活,网络没有学习过,只看了一点点,这一块是参考《Android疯狂讲义》的)

package com.hitwhwlp.love;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
public class ClientThread implements Runnable
{
private Socket s;
// 定义向UI线程发送消息的Handler对象
private Handler handler;
// 定义接收UI线程的消息的Handler对象
public Handler revHandler;
// 该线程所处理的Socket所对应的输入流
BufferedReader br = null;
OutputStream os = null;
int flag;
public ClientThread(Handler handler)
{
this.handler = handler;
}
public void run()
{
try
{
s = new Socket("192.168.1.230", 30000);//这是我的电脑的本机ip地址
br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
os = s.getOutputStream();
// 启动一条子线程来读取服务器响应的数据
new Thread()
{
@Override
public void run()
{
String content = null;
// 不断读取Socket输入流中的内容。
try
{
while ((content = br.readLine()) != null)
{
// 每当读到来自服务器的数据之后,发送消息通知程序界面显示该数据
Message msg = new Message();
msg.what = 0x123;
msg.obj = content;
handler.sendMessage(msg);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}.start();
// 为当前线程初始化Looper
Looper.prepare();
// 创建revHandler对象
revHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
// 接收到UI线程中用户输入的数据
if (msg.what == 0x345)
{
// 将用户在文本框内输入的内容写入网络
try
{
os.write((msg.obj.toString() + "\r\n")
.getBytes("utf-8"));
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
};
// 启动Looper
Looper.loop();
}
catch (SocketTimeoutException e1)
{
System.out.println("网络连接超时!!");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

至于服务端嘛~默默贴出来,不说话

public class MyServer
{// 定义保存所有Socket的ArrayListpublic static ArrayList<Socket> socketList= new ArrayList<Socket>();public static void main(String[] args)throws IOException{ServerSocket ss = new ServerSocket(30000);while(true){// 此行代码会阻塞,将一直等待别人的连接Socket s = ss.accept();socketList.add(s);// 每当客户端连接后启动一条ServerThread线程为该客户端服务new Thread(new ServerThread(s)).start();}}
}
// 负责处理每个线程通信的线程类
public class ServerThread implements Runnable {// 定义当前线程所处理的SocketSocket s = null;// 该线程所处理的Socket所对应的输入流BufferedReader br = null;public ServerThread(Socket s) throws IOException {this.s = s;// 初始化该Socket对应的输入流br = new BufferedReader(new InputStreamReader(s.getInputStream(),"utf-8")); }public void run() {try {String content = null;// 采用循环不断从Socket中读取客户端发送过来的数据while ((content = readFromClient()) != null) {// 遍历socketList中的每个Socket,// 将读到的内容向每个Socket发送一次,除了自己(这个方法自己想的,如果有更高端方法,还请大神赐教,网络的现在暂时不懂)for (Socket i : MyServer.socketList) {if (i != s) {OutputStream os = i.getOutputStream();os.write((content + "\n").getBytes("utf-8"));}}}} catch (IOException e) {e.printStackTrace();}}// 定义读取客户端数据的方法private String readFromClient() {try {return br.readLine();}// 如果捕捉到异常,表明该Socket对应的客户端已经关闭catch (IOException e) {// 删除该Socket。MyServer.socketList.remove(s); }return null;}
}

上一张效果图,这是拿两个机子的对话

Android学习-聊天功能相关推荐

  1. android c聊天功能,Android实现简单C/S聊天室应用

    Android的网络应用:简单的C/S聊天室,供大家参考,具体内容如下 服务器端:提供两个类 创建ServerSocket监听的主类:MyServer.java 负责处理每个Socket通信的线程类: ...

  2. android加入聊天功能,app实现聊天功能 - houwanmin的个人空间 - OSCHINA - 中文开源技术交流社区...

    .  OpenIM(Android)主体功能集成 1.1  前置准备 如果您单纯是想体验OpenIM的功能,建议直接跳过这一步.直接查看快速集成. 在这个集成教程中,我们使用已创建的Demo应用,向您 ...

  3. Android开发聊天功能

    效果图: 具体消息传输参考:https://blog.csdn.net/u011463794/article/details/89482734 项目在github上:https://github.co ...

  4. android php实时聊天工具,Android_Android 应用APP加入聊天功能,简介 自去年 LeanCloud 发布实时 - phpStudy...

    Android 应用APP加入聊天功能 简介 自去年 LeanCloud 发布实时通信(IM)服务之后,基于用户反馈和工程师对需求的消化和对业务的提炼,上周正式发布了「实时通信 2.0 」.设计理念依 ...

  5. Android学习笔记 2.5.3 实例——使用SimpleAdapter创建ListView 2.5.4 自动完成文本框(AutoCompleteTextView)的功能与用法

    Android学习笔记 疯狂Android讲义 文章目录 Android学习笔记 疯狂Android讲义 第2章 Android 应用的界面编程 2.5 第4组 UI组件:AdapterView及其子 ...

  6. Android Studio开发——蓝牙聊天功能

    Android Studio开发--蓝牙聊天功能 蓝牙工作流程 功能要求 实现要点 声明蓝牙权限 添加程序运行的状态描述文本及配色代码 布局文件 蓝牙会话的服务组件ChatService Activi ...

  7. Android实现实时视频聊天功能|源码 Demo 分享

    疫情期间,很多线下活动转为线上举行,实时音视频的需求剧增,在视频会议,在线教育,电商购物等众多场景成了"生活新常态". 本文将教你如何通过即构ZEGO 音视频 SDK 在Andro ...

  8. 写了个Android聊天客户端框架,基本聊天功能、数据库、服务器都有。大家可以看一看。已经开源

    写了个Android聊天客户端框架,基本聊天功能.数据库.服务器都有.大家可以看一看.已经开源(希望两个手机通信的话,改一下pushid就可以) 几点说明: 1:包含的基本功能.: 1.1比如gif动 ...

  9. Android Studio在类微信程序完成“蓝牙聊天功能”实现蓝牙通信

    Android Studio在类微信程序完成"蓝牙聊天功能"实现蓝牙通信 项目运行截图 通信原理 蓝牙权限 strings.xml tab01.xml 菜单文件option_men ...

最新文章

  1. 分布式版本控制系统 Git 教程
  2. float类型为什么不精确等于0_程序中算钱不能用浮点类型是个什么坑?
  3. 004_LoadOnStartup
  4. 权变措施 弹回计划 应急计划的区别
  5. 成功解决TypeError: tuple indices must be integers or slices, not str
  6. Google地图的trip plan是旅行规划的好帮手!
  7. win10 后台运行jar包_win10系统设置双击jar文件直接运行的处理教程
  8. 前端学习(3085):vue+element今日头条管理-封装数据接口
  9. 鲲鹏服务器php性能,对鲲鹏服务器的内存进行性能优化后的前后数据对比
  10. 软件设计师笔记---中央处理单元CPU
  11. MySQL性能优化(二)
  12. C/C++ 活动预处理器
  13. Java_GUI创建单机版QQ聊天小程序并实现简单的小功能(附所有源码)
  14. scala读写linux上的文件,一起学Scala 文件 I/O
  15. SaaSBase:最受欢迎的跨境电商软件有哪些(上篇)
  16. 架构之美第五章-架构概述
  17. 计算机无法读取tf卡,tf卡修复工具不好用教你电脑不识别TF卡的解决办法
  18. python简单聊天工具开发
  19. Illumina测序什么时候会测序到接头序列?
  20. xmind打开文件报错

热门文章

  1. 筋膜枪原理与筋膜枪MCU软硬件方案PCBA方案分享
  2. [kuangbin带你飞]专题四 做题顺序与题解 【最短路练习】
  3. AH2017/HNOI2017 礼物
  4. 谷歌要完,百度也危了
  5. Dz论坛文章随机高亮颜色
  6. FPGA-04 触摸按键控制LED灯
  7. 芯片后端开发基础知识(二)
  8. DC-DC转换器芯片SY8113BADC
  9. Intel与AMD的拼杀
  10. 基于java的物流信息_基于Java EE的物流信息系统的开发设计