聊天室-客户端

现在只能实现群聊,不能实现私聊
图片如下:

登录界面:

在这里插入图片描述

聊天界面:

在这里插入图片描述

在AndroidStudio中可以开启两个模拟器,也可以手机和模拟器,ip地址是电脑的ipv4地址,可以在cmd通过ipconfig查看自己的ipv4地址

登录界面的布局:


<?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="match_parent"
    android:background="@drawable/picture"
    >

    <LinearLayout
        android:orientation="vertical"
        android:layout_marginTop="280dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
       >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="用户名   "
                android:textSize="30sp"
                android:textColor="#0F0F0F"/>

            <EditText
                android:id="@+id/input_name"
                android:gravity="center"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="ip地址  "
                android:textSize="30sp"
                android:textColor="#0F0F0F"/>

            <EditText
                android:id="@+id/ip_address"
                android:gravity="center"
                android:focusable="false"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="端口号  "
                android:textSize="30sp"
                android:textColor="#0F0F0F"/>

            <EditText
                android:id="@+id/port_name"
                android:gravity="center"
                android:focusable="false"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </LinearLayout>


        <Button
            android:id="@+id/login"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="登录"
            android:layout_marginTop="30dp"
            android:textSize="30sp"
            android:background="#F0FFFF"
            android:textColor="#0F0F0F"/>

    </LinearLayout>



</LinearLayout>

登录界面的代码:

package com.example.clientactivity;

import androidx.appcompat.app.ActionBar;
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;

public class MainActivity extends AppCompatActivity {

    private EditText input_name;
    private EditText ip_address;
    private EditText port_name;
    Button login;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
        input_name = findViewById(R.id.input_name);
        ip_address = findViewById(R.id.ip_address);
        ip_address.setText("192.168.43.92");
        port_name = findViewById(R.id.port_name);
        port_name.setText("7567");
        login = findViewById(R.id.login);
        login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String name = input_name.getText().toString();
                String ip = ip_address.getText().toString();
                String port = port_name.getText().toString();
                Intent intent = new Intent(MainActivity.this,Chat.class);//开启第二个界面
                intent.putExtra("name",name);//信息的传递
                intent.putExtra("ip",ip);
                intent.putExtra("port",port);
                startActivity(intent);
            }
        });
    }
}

聊天界面的布局:
聊天界面使用到了RecyclerView,所以在build.gradle添加

implementation 'com.android.support:recyclerview-v7:29.0.1'
<?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="match_parent"
    android:background="@drawable/shappp"
    >



<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <Button
        android:id="@+id/back"
        android:layout_width="53dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:background="@drawable/evvv_shape"
        android:text="退出" />

    <TextView
        android:layout_width="0dp"
        android:layout_marginTop="20dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="聊天室"
        android:textColor="#121212"
        android:textSize="20sp" />


</LinearLayout>



    <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/msg_recycler_view"
         android:layout_marginTop="15dp"
         android:layout_width="match_parent"
         android:layout_marginLeft="15dp"
         android:layout_marginRight="15dp"
         android:layout_height="0dp"
         android:layout_weight="1"/>
    <LinearLayout
        android:layout_margin="15dp"
        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="@drawable/ev_shape"//自定义的布局
            android:hint="Type something here"
            android:maxLines="2"/>


        <Button
            android:id="@+id/send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/evv_shape"
            android:text="发送"
            android:layout_marginLeft="5dp"
            android:textColor="#FFFFFF"
            android:textSize="20sp"/>
    </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="5dp">

    <TextView
        android:id="@+id/get_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>

    <LinearLayout
        android:id="@+id/left_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center"
            android:background="@drawable/ppp" />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">


            <LinearLayout

                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="left"
                android:background="@drawable/left">


                <TextView
                    android:id="@+id/left_msg"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_margin="5dp"

                    android:textColor="#000000" />
            </LinearLayout>

        </LinearLayout>
    </LinearLayout>


    <LinearLayout
        android:id="@+id/right_layout"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right">


        <LinearLayout
            android:layout_width="141dp"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:background="@drawable/right">

            <TextView
                android:id="@+id/right_msg"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_margin="10dp"
                android:textColor="#fff" />

        </LinearLayout>

            <ImageView
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:background="@drawable/zhan"
                android:layout_gravity="center"/>

    </LinearLayout>

</LinearLayout>

所用的气泡和图片可自己在网上找

下面消息接收和发送的显示用的是Android第一行代码中的RecyclerView那一章

package com.example.clientactivity;

public class Msg {

    public static final int TYPE_RECEIVE = 0;
    public static final int TYPE_SENT = 1;
    private String content;
    private int type;
    public Msg(String content,int type) {
        this.content = content;
        this.type = type;
    }
    public String getContent() {
        return content;
    }
    public int getType() {
        return type;
    }
}

适配器:

package com.example.clientactivity;

import android.annotation.SuppressLint;
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.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder> {
    private List<Msg> mMsgList;
    static class ViewHolder extends RecyclerView.ViewHolder {
        LinearLayout leftLayout;
        LinearLayout rightLayout;
        TextView leftMsg;
        TextView rightMsg;
        TextView getTime;
        public ViewHolder(View view) {
            super(view);
            getTime = view.findViewById(R.id.get_time);
            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;
    }
    @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);
        holder.getTime.setText(getCurrentTime());//显示时间
        if(msg.getType() == Msg.TYPE_RECEIVE) {
            holder.leftLayout.setVisibility(View.VISIBLE);
            holder.rightLayout.setVisibility(View.GONE);
            holder.leftMsg.setText(msg.getContent());
        }else if(msg.getType() == Msg.TYPE_SENT) {
            holder.rightLayout.setVisibility(View.VISIBLE);
            holder.leftLayout.setVisibility(View.GONE);
            holder.rightMsg.setText(msg.getContent());
        }
    }

    @Override
    public int getItemCount() {
        return mMsgList.size();
    }

    private static String getCurrentTime() {
        @SuppressLint("SimpleDateFormat")
        String date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
        return date;
    }
}

客户端:


package com.example.clientactivity;

import androidx.appcompat.app.ActionBar;
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.StrictMode;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeoutException;

public class Chat extends AppCompatActivity {
    private List<Msg> msgList = new ArrayList<>();
    private EditText inputText;
    private String name;
    private String ip;
    private String port;
    private Button send;
    private Button back;
    private RecyclerView msgRecyclerView;
    private MsgAdapter adapter;
    private Socket socket ;
    private InputStream receive;
    private OutputStream sendOut;
    private String content;
    private StringBuilder builder = new StringBuilder();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
        inputText = findViewById(R.id.input_text);
        send = findViewById(R.id.send);
        back  =  findViewById(R.id.back);
        msgRecyclerView = findViewById(R.id.msg_recycler_view);
        Intent intent = getIntent();//获取登录界面传过来的信息
        name = intent.getStringExtra("name");
        ip = intent.getStringExtra("ip");
        port = intent.getStringExtra("port");

        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath().build());

        try{
            socket = new Socket(ip,Integer.parseInt(port));
            sendOut = socket.getOutputStream();
            receive = socket.getInputStream();
        }catch (Exception e) {
            e.printStackTrace();
        }

        if(socket == null) {
            Toast.makeText(this,"连接失败",Toast.LENGTH_SHORT).show();
            finish();
        }else{
            Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show();
        }

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        msgRecyclerView.setLayoutManager(layoutManager);
        adapter = new MsgAdapter(msgList);
        msgRecyclerView.setAdapter(adapter);
//客户端接收消息
        new Thread(new Runnable() {
            public void run() {
                try{
                    byte[] arr = new byte[1024 * 6];
                    int len;
                    String receiveMsg;
                    while(true) {
                        while((len = receive.read(arr)) != -1) {
                            receiveMsg = new String(arr,0,len);
                            final Msg msg = new Msg(receiveMsg,Msg.TYPE_RECEIVE);
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    msgList.add(msg);
                                    adapter.notifyItemInserted(msgList.size() - 1);//有新消息时,刷新RecyclerView中的显示
                                    msgRecyclerView.scrollToPosition(msgList.size() - 1);//将RecyclerView定位到最后一行
                                }
                            });
                        }
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

//退出按钮
        back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AlertDialog.Builder dialog = new AlertDialog.Builder(Chat.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();
            }
        });
//客户端发送消息
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try{
                    content = inputText.getText().toString();
                    if(!"".equals(content)) {
                        builder.append(content).append("\n\n").append("from:").append(name);
                        content = builder.toString();
                        try{
                            sendOut.write(content.getBytes("utf-8"));
                            builder.delete(0,builder.length());
                        }catch (Exception e) {
                            e.printStackTrace();
                        }
                        Msg msg = new Msg(content,Msg.TYPE_SENT);
                        msgList.add(msg);
                        adapter.notifyItemInserted(msgList.size() - 1);
                        msgRecyclerView.scrollToPosition(msgList.size() - 1);
                        inputText.setText("");
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

需注册网络权限:

<uses-permission android:name="android.permission.INTERNET" />

注意:

  • 模拟器可以运行,手机端不能正常运行,可以尝试着手机端连接电脑的热点。
  • 模拟器必须在有网条件下才能正常运行
  • 在接收消息的线程中,必须进行UI的更新。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值