安卓多人聊天室客户端

安卓多人聊天室客户端

主活动代码
package com.example.chatroom_client;

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 androidx.appcompat.app.AppCompatActivity;
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.150";
    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 = 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);
        }
    }
}
ChatRoom代码
package com.example.chatroom_client;

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 androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
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.150";
    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(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chat_ui);

        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);
        //每当有新消息时,刷新recycleview中的显示
        adapter.notifyItemInserted(msgList.size() - 1);
        //将recycleview定位到最后一行
        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("");      //在副线程发送完毕后再将待发送信息置空
                }
            }
        }
    }
}

Msg类
package com.example.chatroom_client;

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;
    }
}
RecyclerView的Adapter: MsgAdapter
package com.example.chatroom_client;

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;
    }
}

主活动布局
<?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">

    <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: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: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.150"
        />

    <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:editable="false"
        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:text="连接" />



</RelativeLayout>
聊天室布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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="#3FA2F8">

        <Button
            android:id="@+id/back"
            android:layout_width="30dp"

            android:layout_height="30dp"
            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: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:layout_marginLeft="10dp"
            android:layout_marginRight="5dp"
            android:background="@drawable/shape"
            />

        <Button
            android:id="@+id/send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/shape2"
            android:text="发送" />

    </LinearLayout>


</LinearLayout>
聊天室子布局:每行消息的布局
<?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="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/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_l"
                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_r"
                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="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

另外

在style.xml中将标题栏隐藏

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

在AndroidManif.xml中加入了网络权限

<uses-permission android:name="android.permission.INTERNET"/>
最后看下效果

登陆界面
在这里插入图片描述

发布了14 篇原创文章 · 获赞 4 · 访问量 693

猜你喜欢

转载自blog.csdn.net/qq_43935080/article/details/99291156
今日推荐