服务器源码
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){
new startServer().start();
}
public static ArrayList<UserThread> socketList=new ArrayList<UserThread>();
public static startServer startServer;
static class startServer extends Thread{
public void run(){
try{
ServerSocket serverSocket = new ServerSocket(6666);
while(true){
Socket socket = serverSocket.accept();
System.out.println(""+socket);
UserThread userThread = new UserThread(socket);
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;
}
@Override
public void run(){
try{
dos= new DataOutputStream(skt.getOutputStream());
dis= new DataInputStream(skt.getInputStream());
String recMsg ="";
while(true){
if(!"".equals(recMsg=dis.readUTF())){
System.out.println("收到一条消息"+ recMsg);
for(UserThread s:socketList){
if(s.equals(this)){
continue;
}
try{
s.getDos().writeUTF(recMsg);
}catch(IOException e){
socketList.remove(s);
e.printStackTrace();
}
}
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;
@Override
protected 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.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#3FA2F8">
<TextView
android: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"-->
<!--/>-->
<TextView
android: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" />
<EditText
android: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" />
<TextView
android: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"
/>
<EditText
android:id="@+id/et_ip"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="192.168.1.66"
/>
<TextView
android: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" />
<EditText
android: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"
/>
<Button
android: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()){
@Override
public void handleMessage(@NonNull Message msg){
if(!recMsg.isEmpty()){
addNewMessage(recMsg,Msg.TYPE_RECEIVED);
}
}
};
@Override
protected 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(){
@Override
public void onClick(View view){
AlertDialog.Builder dialog= new AlertDialog.Builder(ChatRoom.this);
dialog.setTitle("退出");
dialog.setMessage("退出登录?");
dialog.setCancelable(false);
dialog.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
});
dialog.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
dialog.show();
}
});
runOnUiThread(new Runnable() {
@Override
public 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(){
@Override
public 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);
}
}
}
}
@Override
public 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{
@Override
public 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.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#187C8F">
<Button
android:id="@+id/back"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:background="@drawable/back" />
<TextView
android: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.RecyclerView
android:id="@+id/msg_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@drawable/background" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/input_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#ffffff"
/>
<Button
android: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"
>
<LinearLayout
android:id="@+id/left_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
>
<ImageView
android:id="@+id/iv_head_others"
android:background="@drawable/headofothers"
android:layout_marginTop="20dp"
android:layout_width="60dp"
android:layout_height="60dp" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/others_name"
android:layout_gravity="left"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android: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>
<LinearLayout
android:id="@+id/right_layout"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/my_name"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android: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>
<ImageView
android: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
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType){
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);
return new ViewHolder(view);
}
@Override
public 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());
}
}
@Override
public 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">
<solid
android:color="#07D0F3"/>
</selector>
previous.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="#0fffff"/>
</selector>
click.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<corners
android: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"/>
<application
android: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是我选中的一张图片