Android聊天室(源码)

服务器源码

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;
        }
        @Override
        public 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;
    @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()){//获取当前进程的Looper对象传给handler
        @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();//finish()是在程序执行的过程中使用它来将对象销毁,finish()方法用于结束一个Activity的生命周期
                    }
                });
                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){
        //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.xml
        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是我选中的一张图片

你可能感兴趣的:(Android)