服务器源码

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;public class Server {public static void main(String[] args){//startServer=new startServer();new startServer().start();//new 一个线程对象开始启动(由于startServer类继承了Thread)}public static ArrayList<UserThread> socketList=new ArrayList<UserThread>();//创建一个泛型是UserThread(UserThread是下面的一个类)的动态数组public static startServer startServer;static class startServer extends Thread{public void run(){try{ServerSocket serverSocket = new ServerSocket(6666);//创建端口值为:6666的ServerSocket对象while(true){//死循环Socket socket = serverSocket.accept();//创建socket对象,用于接受客户端的请求System.out.println(""+socket);//用于显示客户端的IP地址,客户端的端口号,以及电脑的端口号UserThread userThread = new UserThread(socket);//通过下面定义的UserTread的有参构造,创建userThread对象Server.socketList.add(userThread);new Thread(userThread).start();//开启输入输出流线程}}catch(IOException e){e.printStackTrace();}}}static class UserThread implements Runnable{private Socket skt;private DataOutputStream dos;private DataInputStream dis;public DataOutputStream getDos(){//返回输出流return dos;}public void setDos(DataOutputStream dos){//给输出流传递参数this.dos=dos;}public DataInputStream getDis(){//返回输入流return dis;}public void setDis(DataInputStream dis){//给输入流传递参数this.dis=dis;}public UserThread(Socket socket){//构造有参构造skt=socket;}@Overridepublic void run(){try{dos= new DataOutputStream(skt.getOutputStream());//获取输出流(准备从服务器给其他的客户端发消息)dis= new DataInputStream(skt.getInputStream());//接收客户端发过来的消息(输入流)String recMsg ="";while(true){//使服务器无限循环if(!"".equals(recMsg=dis.readUTF())){//读取输入流的消息,并把消息传到recMsg中System.out.println("收到一条消息"+ recMsg);//显示:收到一条消息+“传入的消息”for(UserThread s:socketList){//增强for循环if(s.equals(this)){continue;}try{s.getDos().writeUTF(recMsg);//将UTF-8的字符串写入字节流}catch(IOException e){socketList.remove(s);//将s从动态数组socketList中删除e.printStackTrace();}}recMsg="";//recMsg内容重新刷新}}}catch(IOException e){e.printStackTrace();}}}
}

客户端源码

MainActivity

package com.example.my_chatroom;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;import java.io.OutputStream;
import java.net.Socket;public class MainActivity extends AppCompatActivity implements View.OnClickListener{private OutputStream outputStream=null;private Socket socket=null;private String ip="192.168.1.66";private Button btn_cnt;private EditText et_ip;private EditText et_name;private EditText et_port;private TextView myName;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn_cnt = (Button)findViewById(R.id.btn_cnt);et_ip=findViewById(R.id.et_ip);et_port=findViewById(R.id.et_port);et_name=findViewById(R.id.et_name);myName=findViewById(R.id.my_name);btn_cnt.setOnClickListener(MainActivity.this);}public void onClick(View view){String name = et_name.getText().toString();if("".equals(name)){Toast.makeText(this, "请输入用户名:", Toast.LENGTH_SHORT).show();}else{Intent intent = new Intent(MainActivity.this,ChatRoom.class);intent.putExtra("name",et_name.getText().toString());intent.putExtra("ip",et_ip.toString());intent.putExtra("port",et_port.toString());startActivity(intent);}}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/picture"><androidx.appcompat.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="#3FA2F8"><TextViewandroid:id="@+id/tv_room"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="登陆聊天室"android:textColor="#F3F4F5"android:textSize="20sp" /></androidx.appcompat.widget.Toolbar><!--<View--> //注意大写,否则闪退<!--android:id="@+id/ver_view"--><!--android:layout_toLeftOf="@+id/text_ip"--><!--android:layout_width="0dp"--><!--android:layout_height="match_parent"--><!--/>--><TextViewandroid:id="@+id/tv_name"android:text="用户名"android:textSize="20sp"android:gravity="center"android:layout_marginBottom="8dp"android:layout_above="@+id/et_ip"android:layout_marginLeft="45dp"android:layout_width="wrap_content"android:layout_height="wrap_content" /><EditTextandroid:id="@+id/et_name"android:layout_toRightOf="@id/tv_name"android:layout_above="@id/et_ip"android:layout_width="150dp"android:gravity="center"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/text_ip"android:text="IP"android:textSize="20sp"android:layout_toLeftOf="@+id/et_ip"android:layout_marginTop="5dp"android:layout_width="60dp"android:layout_height="wrap_content"android:layout_below="@+id/tv_name"/><EditTextandroid:id="@+id/et_ip"android:layout_width="150dp"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="192.168.1.66"/><TextViewandroid:id="@+id/tv_port"android:layout_below="@+id/text_ip"android:layout_marginLeft="45dp"android:text="端口"android:textSize="20sp"android:layout_marginTop="20dp"android:layout_width="wrap_content"android:layout_height="wrap_content" /><EditTextandroid:id="@+id/et_port"android:layout_width="150dp"android:layout_height="wrap_content"android:text="6666"android:gravity="center"android:layout_below="@+id/et_ip"android:layout_marginLeft="20dp"android:layout_toRightOf="@id/tv_port"/><Buttonandroid:id="@+id/btn_cnt"android:layout_width="100dp"android:layout_height="wrap_content"android:layout_below="@id/et_port"android:layout_marginLeft="130dp"android:layout_marginTop="30dp"android:background="#07D0F3"android:textColor="#ffffff"android:text="连接" /></RelativeLayout>

ChatRoom

package com.example.my_chatroom;import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;public class ChatRoom extends AppCompatActivity implements View.OnClickListener{private List<Msg> msgList = new ArrayList<>();private EditText inputText;private Button send;private Button back;private RecyclerView msgRecyclerView;private MsgAdapter adapter;private Socket socketSend;private String ip="192.168.1.66";private String port="6666";DataInputStream dis;DataOutputStream dos;boolean isRunning = false;private TextView myName;private String recMsg;private boolean isSend=false;private String name;private Handler handler = new Handler(Looper.myLooper()){//获取当前进程的Looper对象传给handler@Overridepublic void handleMessage(@NonNull Message msg){//?if(!recMsg.isEmpty()){addNewMessage(recMsg,Msg.TYPE_RECEIVED);//添加新数据}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_chat_room);Intent intent =getIntent();name=intent.getStringExtra("name");inputText = findViewById(R.id.input_text);send=findViewById(R.id.send);send.setOnClickListener(this);back = findViewById(R.id.back);back.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View view){AlertDialog.Builder dialog= new AlertDialog.Builder(ChatRoom.this);dialog.setTitle("退出");dialog.setMessage("退出登录?");dialog.setCancelable(false);dialog.setPositiveButton("是", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {finish();//finish()是在程序执行的过程中使用它来将对象销毁,finish()方法用于结束一个Activity的生命周期}});dialog.setNegativeButton("否", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {}});dialog.show();//让返回键开始启动}});runOnUiThread(new Runnable() {@Overridepublic void run() {LinearLayoutManager layoutManager = new LinearLayoutManager(ChatRoom.this);msgRecyclerView= findViewById(R.id.msg_recycler_view);msgRecyclerView.setLayoutManager(layoutManager);adapter = new MsgAdapter(msgList);msgRecyclerView.setAdapter(adapter);}});new Thread(new Runnable(){@Overridepublic void run(){try{if((socketSend = new Socket(ip,Integer.parseInt(port)))==null){Log.d("ttw","发送了一条消息1");}else{isRunning = true;Log.d("ttw","发送了一条消息2");dis = new DataInputStream(socketSend.getInputStream());dos = new DataOutputStream(socketSend.getOutputStream());new Thread(new receive(),"接收线程").start();new Thread(new Send(),"发送线程").start();}}catch(Exception e){isRunning = false;e.printStackTrace();Looper.prepare();Toast.makeText(ChatRoom.this, "连接服务器失败!!!", Toast.LENGTH_SHORT).show();Looper.loop();try{socketSend.close();}catch(IOException e1){e1.printStackTrace();}finish();}}}).start();}public void addNewMessage(String msg,int type){Msg message = new Msg(msg,type);msgList.add(message);adapter.notifyItemInserted(msgList.size()-1);msgRecyclerView.scrollToPosition(msgList.size()-1);}class receive implements Runnable{public void run(){recMsg = "";while(isRunning){try{recMsg = dis.readUTF();Log.d("ttw","收到了一条消息"+"recMsg: "+ recMsg);}catch(Exception e){e.printStackTrace();}if(!TextUtils.isEmpty(recMsg)){Log.d("ttw","inputStream:"+dis);Message message = new Message();message.obj=recMsg;handler.sendMessage(message);}}}}@Overridepublic void onClick(View view){String content = inputText.getText().toString();@SuppressLint("SimpleDateFormat")String date = new SimpleDateFormat("hh:mm:ss").format(new Date());StringBuilder sb = new StringBuilder();sb.append(content).append("\n\n"+date);content = sb.toString();if(!"".equals(content)){Msg msg = new Msg(content,Msg.TYPE_SENT);msgList.add(msg);adapter.notifyItemInserted(msgList.size()-1);msgRecyclerView.scrollToPosition(msgList.size()-1);isSend = true;}sb.delete(0,sb.length());}class Send implements Runnable{@Overridepublic void run(){while(isRunning){String content = inputText.getText().toString();Log.d("ttw","发了一条消息");if(!"".equals(content)&&isSend){@SuppressLint("SimpleDateFormat")String date = new SimpleDateFormat("hh:mm:ss").format(new Date());StringBuilder sb = new StringBuilder();sb.append(content).append("\n\n来自:").append(name).append("\n"+date);content = sb.toString();try{dos.writeUTF(content);sb.delete(0,sb.length());Log.d("ttw","发送了一条消息");}catch(IOException e){e.printStackTrace();}isSend = false;inputText.setText("");}}}}
}

activity_chat_room.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical"android:background="#d8e0e8"android:layout_width="match_parent"android:layout_height="match_parent"><androidx.appcompat.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="#187C8F"><Buttonandroid:id="@+id/back"android:layout_width="50dp"android:layout_height="wrap_content"android:background="@drawable/back" /><TextViewandroid:id="@+id/text_room"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="聊天室"android:textColor="#F3F4F5"android:textSize="20sp" /></androidx.appcompat.widget.Toolbar><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/msg_recycler_view"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:background="@drawable/background" /><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><EditTextandroid:id="@+id/input_text"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:background="#ffffff"/><Buttonandroid:id="@+id/send"android:layout_width="wrap_content"android:layout_height="50dp"android:background="#07D0F3"android:text="发送"android:textColor="#ffffff" /></LinearLayout></LinearLayout>

msg_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="10dp"><LinearLayoutandroid:id="@+id/left_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="left"><ImageViewandroid:id="@+id/iv_head_others"android:background="@drawable/headofothers"android:layout_marginTop="20dp"android:layout_width="60dp"android:layout_height="60dp" /><LinearLayoutandroid:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:id="@+id/others_name"android:layout_gravity="left"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/left_msg"android:textStyle="bold"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:layout_marginBottom="5dp"android:background="@drawable/qipao_2"android:layout_gravity="center"android:textColor="#B955B9" /></LinearLayout></LinearLayout><LinearLayoutandroid:id="@+id/right_layout"android:layout_gravity="right"android:layout_width="wrap_content"android:layout_height="wrap_content"><LinearLayoutandroid:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:id="@+id/my_name"android:layout_gravity="right"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/right_msg"android:textStyle="bold"android:layout_gravity="center"android:background="@drawable/qipao_1"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout><ImageViewandroid:id="@+id/iv_head_my"android:background="@drawable/headofmy"android:layout_marginTop="20dp"android:layout_width="60dp"android:layout_height="60dp" /></LinearLayout>
</LinearLayout>

Msg

package com.example.my_chatroom;public class Msg {public static final int TYPE_RECEIVED=0;public static final int TYPE_SENT =1;public String getContent(){return content;}public int getType(){return type;}private String content;private int type;public Msg(String content,int type){this.content=content;this.type=type;}
}

MsgAdapter

package com.example.my_chatroom;import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;import java.util.List;public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder> {private List<Msg> mMsgList;@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType){//ViewHolder通常出现在适配器里,为的是listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能。View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);//LayoutInflat.from()从一个Context中,获得一个布局填充器,这样你就可以使用这个填充器来把xml布局文件转为View对象了。//LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);这样的方法来加载布局msg_item.xmlreturn new ViewHolder(view);}@Overridepublic void onBindViewHolder(@NonNull 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.leftLayout.setVisibility(View.GONE);holder.rightLayout.setVisibility(View.VISIBLE);holder.rightMsg.setText(msg.getContent());}}@Overridepublic int getItemCount(){return mMsgList.size();}static class ViewHolder extends RecyclerView.ViewHolder{LinearLayout leftLayout;LinearLayout rightLayout;TextView leftMsg;TextView rightMsg;public ViewHolder(@NonNull 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);}}public MsgAdapter (List<Msg> msgList){mMsgList = msgList;}
}

shape.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><solidandroid:color="#07D0F3"/>
</selector>

previous.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><solidandroid:color="#0fffff"/>
</selector>

click.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><cornersandroid:radius="20dp"/><item android:drawable="@drawable/shape"android:state_enabled="true"android:state_pressed="true"/><item android:drawable="@drawable/previous"android:state_enabled="true"android:state_pressed="false"/>
</selector>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.my_chatroom"><uses-permission android:name="android.permission.INTERNET"/><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="聊天室"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".ChatRoom"/><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

另外,在说明一点,如果需要修改App图标的话

路径:

修改位置:

其中theme是我选中的一张图片

Android聊天室(源码)相关推荐

  1. Android聊天室源码开发,悬浮窗的实现及封装思路

    为了实现语音聊天室源码的多场景应用,悬浮小窗口在语音聊天室源码开发中还是比较常见的需求,主要是指用户在语音连麦过程中打开其它界面或者退到桌面时语音连麦不会中断且会有一个悬浮小窗口位于最上层,接下来我们 ...

  2. 聊天室平台搭建【免费下载 无需积分/C币】java、Android、php多平台聊天室源码打包下载

    关键词:多款聊天平台源码合集免费下载 #聊天源码,#聊天工具,#源码下载,#仿QQ,#聊天室源码 聊天室平台搭建 搭建自己的聊天交流平台 [点击此处]下载源码 原网址:https://download ...

  3. YShout一款PHP+TXT+Ajax嵌入式在线聊天室源码

    简介: YShout是一款PHP+TXT+AJAX开发嵌入式在线聊天室源码,UTF-8编码. 可以非常方便的嵌入到的你的网站中,无需数据库,采用TXT存储数据,小巧灵活,移植方便.采用AJAX技术,增 ...

  4. 使用 Redis 实现语音社交聊天室源码中的排行榜功能

    在语音社交聊天室源码中,排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择. 一般语音社交聊天室源码的排行榜都是有实效性的,比如"用户积分榜&quo ...

  5. 仿9158 VC++视频聊天室源码

    视频聊天室源码简介: 成熟产品可提供全套系统源代码(包服务端,客户端,网站平台) 采用C++语言开发系统速度快,稳定.H264视频编解码视频清晰,流畅,同时3路视频

  6. 高清视频会议 视频聊天室源码下载

    高清视频会议.视频聊天室源码简介: "SDK即时通讯平台"是一套跨平台的即时通讯解决方案,基于先进的H.264视频编码标准.AAC音频编码标准与P2P技术,支持高清视频,整合了佰锐 ...

  7. 语音聊天室源码中的变声,应用了哪些算法?

    导读:2021开年以来,语音聊天室源码伴随着Clubhouse的爆火再获资本的关注,国内相关产品都迎来了股价的大幅上涨,预计未来音频化在社交领域还会有长期且广泛的需求. 在移动互联网技术加持下,语音聊 ...

  8. 语音聊天室源码开发点赞功能,用 MySQL 还是 Redis ?

    为了提升用户在语音聊天室源码中的互动性,一般在开发动态广场功能时会支持用户间对动态进行点赞,所以点赞功能可以说是语音聊天室源码开发的基础性功能,今天我们就来聊聊点赞.评论.收藏等这些场景的db数据库设 ...

  9. 开源版-在线客服系统源码_网页聊天室源码_webim

    2019独角兽企业重金招聘Python工程师标准>>> WoLive是一款在线客服系统源码,支持PC Web和移动端,只需嵌入一段js代码即可快速接入.购买后可私有化部署,WoLiv ...

  10. 出售视频聊天室源码 功能类似 YY 齐秀

    出售视频聊天室源码 功能类似 YY  齐秀 转载于:https://www.cnblogs.com/sxsoft/archive/2012/05/16/2504398.html

最新文章

  1. 浅析网站SEO与网站建设密不可分的关系
  2. 常用API-3(System类、Math类、Arrays类、正则表达式)
  3. hadoop学习3 查找块的位置
  4. 分披萨问题_比萨疯狂问题
  5. 【前端】第三章 Vue
  6. 艾伟_转载:.NET Discovery 系列之二--string从入门到精通(勘误版下)
  7. VBA中让程序休眠 SLeep的方法
  8. 【BZOJ1417】Pku3156 Interconnect
  9. 螺旋传动设计系统lisp_石狮螺旋输送机质量可靠
  10. (最简单)uniapp微信小程序生成二维码图片插件
  11. Django开发教程 第一节 HelloWorld
  12. python计算梯形面积程序编程解题思路_编写程序计算梯形面积
  13. 钻石小鸟:年轻兄妹的百年品牌梦
  14. 精心整理史上最全的数据结构flash演示动画,共5个版本,祝大家考研成功!
  15. 无线固话新型诈骗技术防范
  16. 抖音卡点视频怎么制作
  17. linux下c/c++读取txt文件,多行文件,且每行都用逗号隔开
  18. 基于Cellar的交互式单细胞数据分析
  19. cc9.3 indesign_Adobe InDesign CC经典教程
  20. Kafka-Broker Spread,Broker Skewed,Broker Leader Skewed指标含义

热门文章

  1. 线路板板SMT贴片中二极管正负极区分方法
  2. java commons math_Apache Commons Math
  3. 【转】乱码翻译全攻略
  4. UG标准件库的使用方法
  5. WPF AvalonDock拖拽布局学习整理
  6. 邮件营销的5个关键数字
  7. 李炎恢html5资源,李炎恢HTML5视频资料分享
  8. CMD 下载并运行软件 Cmd Bat Powershell
  9. 生成对抗网络GANs的用途
  10. 清华自动化大一 C++作业引爆全网,特奖得主、阿里P6:我们也做不到