聊天室简介

  • 简单介绍
  • 更换图标
  • 网络权限
  • 登录界面
    • activity_main.xml
    • MainActivity.java
  • 选择头像
    • activity_choose_picture.xml
    • ChoosePicture.java
  • 客户端
    • ChatRoom.java
    • activity_chat_room.xml
    • msg_item.xml
    • Msg.java
    • MsgAdapter.java
  • 服务器

简单介绍

Android的第二个小程序,初步实现了换头像功能、多人聊天功能。先放几张照片亮亮相吧:




更换图标

在drawale文件夹中加入.png的一张照片即可

android:icon="@drawable/icon"

网络权限

保险起见3条全加,当时只加了一条然后就连不上网。。。

    package="com.example.chartroom"><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><application

登录界面

注意实时查看你连的WIFI的IP地址,Win+R输入CMD,再输入ipconfig/all查看WIFI那一栏中的IPV4

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/bd1"android:orientation="vertical">//这可以把上面标题改掉<androidx.appcompat.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#2FF1EEEE"><TextViewandroid:id="@+id/tv_room"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:gravity="center"android:text="欢迎登录聊天室"android:textColor="#93FFFFFF"android:textSize="19sp" /></androidx.appcompat.widget.Toolbar><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:layout_marginLeft="50sp"android:layout_marginRight="50sp"android:layout_marginTop="100dp"><TextViewandroid:id="@+id/tv_name"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:text="用户名"android:textSize="20sp"android:textColor="#93FFFFFF"/><EditTextandroid:id="@+id/et_name"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:gravity="center"android:textColor="#93FFFFFF"android:theme="@style/CretateRoomEditTextTheme"/></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:layout_marginLeft="50sp"android:layout_marginRight="50sp"android:layout_marginTop="50dp"><TextViewandroid:id="@+id/tv_ip"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:text="IP地址"android:textSize="20sp"android:textColor="#93FFFFFF"/><EditTextandroid:id="@+id/et_ip"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:gravity="center"       android:text="192.168.1.5" android:textColor="#93FFFFFF"android:theme="@style/CretateRoomEditTextTheme" /></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:layout_marginLeft="50sp"android:layout_marginRight="50sp"android:layout_marginTop="50dp"><TextViewandroid:id="@+id/tv_port"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:text="端口"android:textSize="20sp"android:textColor="#93FFFFFF"/><EditTextandroid:id="@+id/et_port"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:gravity="center"android:textColor="#93FFFFFF"android:theme="@style/CretateRoomEditTextTheme"android:text="6666"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"android:layout_gravity="center"android:layout_marginLeft="60sp"android:layout_marginRight="50sp"android:layout_marginTop="50dp"><Buttonandroid:id="@+id/login"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight = "1"android:layout_gravity="center"android:gravity="center"android:layout_margin="30dp"android:textColor="#93FFFFFF"android:textSize="16sp"android:background="@drawable/change"android:text="连接"/><Buttonandroid:id="@+id/quit"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight = "1"android:layout_gravity="center"android:gravity="center"android:layout_margin="30dp"android:textColor="#93FFFFFF"android:textSize="16sp"android:background="@drawable/change"android:text="退出"/></LinearLayout></LinearLayout>

MainActivity.java

package com.example.chartroom;import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
import android.content.DialogInterface;
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;public class MainActivity extends AppCompatActivity {private Button login;private Button quit;private EditText et_name;private EditText et_ip;private EditText et_port;private TextView my_name;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//获取id,连接控件login = (Button) findViewById(R.id.login);quit = (Button) findViewById(R.id.quit);et_name = findViewById(R.id.et_name);et_ip = (EditText) findViewById(R.id.et_ip);et_port = (EditText) findViewById(R.id.et_port);//login点击事件login.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//获取一个视图View对象里的字符串String name = et_name.getText().toString();//如果没输入名字if("".equals(name)){Toast.makeText(MainActivity.this, "请输入用户名!", Toast.LENGTH_SHORT).show();}else{Intent intent = new Intent(MainActivity.this,ChoosePicture.class);//向下一活动传递信息                                        intent.putExtra("name",et_name.getText().toString());intent.putExtra("ip",et_ip.getText().toString());intent.putExtra("port",et_port.getText().toString());                    try{startActivity(intent);}catch(Exception e){System.out.println("开启失败");finish();}                 }}});//quit点击事件quit.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//用AlertDialog显示一个退出提示框AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);dialog.setTitle("关闭提示");dialog.setMessage("确定退出登录?");dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {System.exit(0);}});dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {}});dialog.show();}});}
}

选择头像

activity_choose_picture.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/bd1"android:orientation="vertical"><androidx.appcompat.widget.Toolbarandroid:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#2FF1EEEE"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:gravity="center"android:text="选择一个喜欢的头像"android:textColor="#93FFFFFF"android:textSize="19sp" /></androidx.appcompat.widget.Toolbar><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:id="@+id/one"android:layout_width="0dp"android:layout_height="115dp"android:layout_weight="1"android:background="@drawable/headofothers"android:layout_margin="10dp"/><Buttonandroid:id="@+id/two"android:layout_width="0dp"android:layout_height="115dp"android:layout_weight="1"android:background="@drawable/headofmy"android:layout_margin="10dp"/><Buttonandroid:id="@+id/three"android:layout_width="0dp"android:layout_height="115dp"android:layout_weight="1"android:background="@drawable/three"android:layout_margin="10dp"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:id="@+id/four"android:layout_width="0dp"android:layout_height="115dp"android:layout_weight="1"android:background="@drawable/six"android:layout_margin="10dp"/><Buttonandroid:id="@+id/five"android:layout_width="0dp"android:layout_height="115dp"android:layout_weight="1"android:background="@drawable/four"android:layout_margin="10dp"/><Buttonandroid:id="@+id/six"android:layout_width="0dp"android:layout_height="115dp"android:layout_weight="1"android:background="@drawable/five"android:layout_margin="10dp"/></LinearLayout></LinearLayout>

ChoosePicture.java

package com.example.chartroom;import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;public class ChoosePicture extends AppCompatActivity implements View.OnClickListener{private String et_name;private String et_ip;private String et_port;@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_choose_picture);System.out.println("启动2");//启动活动,并获取传递过来的信息Intent intent = getIntent();//传入键值得到数据et_name = intent.getStringExtra("name");et_ip = intent.getStringExtra("ip");et_port = intent.getStringExtra("port");Button button1 = (Button)findViewById(R.id.one);Button button2 = (Button)findViewById(R.id.two);Button button3 = (Button)findViewById(R.id.three);Button button4 = (Button)findViewById(R.id.four);Button button5 = (Button)findViewById(R.id.five);Button button6 = (Button)findViewById(R.id.six);button1.setOnClickListener(this);button2.setOnClickListener(this);button3.setOnClickListener(this);button4.setOnClickListener(this);button5.setOnClickListener(this);button6.setOnClickListener(this);}@Overridepublic void onClick(View view) {//向下一活动传递信息Intent intent = new Intent(ChoosePicture.this,ChatRoom.class);intent.putExtra("name",et_name.toString());intent.putExtra("ip",et_ip.toString());intent.putExtra("port",et_port.toString());switch(view.getId()){case R.id.one:intent.putExtra("imageId",R.drawable.headofothers);break;case R.id.two:intent.putExtra("imageId",R.drawable.headofmy);break;case R.id.three:intent.putExtra("imageId",R.drawable.three);break;case R.id.four:intent.putExtra("imageId",R.drawable.six);break;case R.id.five:intent.putExtra("imageId",R.drawable.four);break;case R.id.six:intent.putExtra("imageId",R.drawable.five);break;}startActivity(intent);}}

客户端

这是将信息传出和接收传入信息的重要板块,其中涉及到IO流、多线程、网络编程等知识。大家可以先复习一遍再来写这一块。

ChatRoom.java

package com.example.chartroom;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import android.annotation.SuppressLint;
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.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 MsgAdapter adapter;private Button back;                //退回键private RecyclerView recyclerView;  //对话显示框private EditText input_text;        //输入框private int imageId ;               //获取自己的头像private int his_imageId;            //获取对方发头像private String time;                //获取时间private Button send;                //发送按钮private String name;                //从主活动获取的名字private String hisName;             //对方昵称,从自定义的receive线程中获取,便于和自己的昵称区分private String content;             //获取对话内容private String ip ;                 //获取ip地址private String port;                //获取端口号private Socket socketSend;          //套接字,用于绑定ip号和端口号便于计算机之间的传输消息private DataInputStream dis;        //码头private DataOutputStream dos;       //集装箱private String recMsg;boolean isRunning = false;          //判断线程是否运行boolean isSend = false;             //判断是否发送@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_chat_room);//启动活动,并获取传递过来的信息Intent intent = getIntent();//传入键值得到数据name = intent.getStringExtra("name");ip = intent.getStringExtra("ip");port = intent.getStringExtra("port");//取出int要指定key,还要设置默认值,当intent中没有该key对应的value时,返回设置的默认值imageId = intent.getIntExtra("imageId",0);//获取实例input_text = (EditText) findViewById(R.id.input_text);back = (Button) findViewById(R.id.back);send = (Button) findViewById(R.id.send);//注册监听器back.setOnClickListener(this);send.setOnClickListener(this);//将RecyclerView和list建立联系(建立与适配器关系啥的)LinearLayoutManager layoutManager = new LinearLayoutManager(ChatRoom.this);recyclerView = (RecyclerView) findViewById(R.id.msg_recycler_view);recyclerView.setLayoutManager(layoutManager);adapter = new MsgAdapter(msgList);recyclerView.setAdapter(adapter);//如果要连网的话就不能在主线程上操作,所以要另外开启一条线程new Thread(new Runnable() {@Overridepublic void run() {try {System.out.println("号码");socketSend = new Socket(ip, Integer.parseInt(port));isRunning = true;dis = new DataInputStream(socketSend.getInputStream());dos = new DataOutputStream(socketSend.getOutputStream());System.out.println("打开dos");//开一条线程接收服务器传来的信息new Thread(new receive(), "接收线程").start();System.out.println("打开线程");} catch (Exception e) {Log.e("TAG",e.toString());e.printStackTrace();//为当前线程准备消息队列Looper.prepare();//Toast只有在主线程中能显示出来Toast.makeText(ChatRoom.this, "连接服务器失败", Toast.LENGTH_SHORT).show();//开启循环取消息Looper.loop();}}}).start();}//获取当前时间public String getCurrentTime(){Date d = new Date();//设置显示的时间格式SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");//以这种格式显示return sdf.format(d);}@Overridepublic void onClick(View view) {switch(view.getId()){case R.id.back:finish();break;case R.id.send://显示时间time = getCurrentTime();String content = input_text.getText().toString();//显示信息StringBuilder sb = new StringBuilder();sb.append(content);if(!"".equals(content)){  //发送信息不为空isSend = true;new Thread(new Runnable() {@Overridepublic void run() {String content = input_text.getText().toString();Log.d("ttw","发了一条消息");System.out.println("content = "+content);System.out.println("传入发送信息");if(!"".equals(content) && isSend){String date = getCurrentTime();try {if(!"".equals(date) && !"".equals(name)){dos.writeUTF(date);dos.writeUTF(content);dos.writeUTF(name);dos.writeUTF(String.valueOf(imageId));System.out.println("发送完了");}} catch (IOException e) {e.printStackTrace();}isSend = false;}}}).start();Msg msg = new Msg(content,Msg.TYPE_SENT,time,name,imageId);   //发送消息System.out.println("imageId = "+imageId);msgList.add(msg);//当有新消息时,刷新ListView中的消息adapter.notifyItemInserted(msgList.size()-1);//将LestView定位到最后一行recyclerView.scrollToPosition(msgList.size()-1);input_text.setText("");}else{Toast.makeText(ChatRoom.this, "不可发送空信息!", Toast.LENGTH_SHORT).show();}sb.delete(0,sb.length());break;default:break;}}//子线程与主线程通过Handler来进行通信。子线程可以通过Handler来通知主线程进行UI更新。//Handler有两个主要的用途:(1)安排消息和可运行对象在将来的某个时间点执行;(2)将一个要在不同的线程上执行的动作编入队列。private Handler handler = new Handler(Looper.myLooper()){@Overridepublic void handleMessage(@NonNull Message msg) {if(!recMsg.isEmpty()){System.out.println("更新消息");addNewMessage(content,Msg.TYPE_RECEIVED,time,hisName,his_imageId);  //刷新接收的消息}}};public void addNewMessage(String msg,int type,String time,String name,int his_imageId){Msg message = new Msg(msg,type,time,name,his_imageId);msgList.add(message);//当有消息时,通知列表有新的数据插入,刷新recyclerview中消息adapter.notifyItemInserted(msgList.size()-1);//将消息一直放在显示屏的底部不随意跑上去recyclerView.scrollToPosition(msgList.size()-1);}//接收线程class receive implements Runnable{@Overridepublic void run() {recMsg = "";while(isRunning){System.out.println("开始接收线程receive");Msg msg = null;try {time = dis.readUTF();content = dis.readUTF();hisName = dis.readUTF();his_imageId = Integer.parseInt(dis.readUTF());System.out.println("接收信息 = "+content);recMsg = hisName + time + content;msg = new Msg(content,Msg.TYPE_RECEIVED,time,hisName,his_imageId);} catch (Exception e) {System.out.println("接受失败");e.printStackTrace();}//判断是否为空字符串if(!TextUtils.isEmpty(recMsg)){System.out.println("查看名字"+msg.getName());Message message = new Message();message.obj = msg;handler.sendMessage(message);}}}}}

activity_chat_room.xml

要显示<这个标识符的话,得写成:"&#060,"

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/bd2"android:orientation="vertical"><androidx.appcompat.widget.Toolbarandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="#2FF1EEEE"><Buttonandroid:id="@+id/back"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#FFFFFF"android:textSize="30sp"android:background="#00FFFFFF"android:text="<"/><TextViewandroid:id="@+id/tv_room"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="ChatRoom"android:textColor="#CDFFFFFF"android:textSize="23sp" /></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" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginRight="10dp"android:layout_marginLeft="10dp"><EditTextandroid:id="@+id/input_text"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:layout_margin="10dp"android:hint="Type Something"android:maxLines="2" /><Buttonandroid:id="@+id/send"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="10dp"android:text="Send"android:textColor="#AAFFFFFF"/></LinearLayout></LinearLayout>

msg_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical">
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:layout_marginTop="20dp"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"><TextViewandroid:id="@+id/time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:gravity="center"android:textSize="15dp" /></LinearLayout></LinearLayout><LinearLayoutandroid:id="@+id/left_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="left"android:layout_marginTop="5dp"><ImageViewandroid:id="@+id/head_others"android:layout_marginRight="5dp"android:layout_width="60dp"android:layout_height="60dp" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"android:layout_marginLeft="5dp"><TextViewandroid:id="@+id/others_name"android:layout_gravity="left"android:layout_width="wrap_content"android:layout_height="0dp"android:layout_weight="1"/><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="0dp"android:layout_weight="2"android:background="@drawable/his_bubble"><TextViewandroid:id="@+id/left_msg"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:gravity="center"android:textColor="@color/black"android:layout_margin="8dp"android:textSize="20dp" /></LinearLayout></LinearLayout></LinearLayout><LinearLayoutandroid:id="@+id/right_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="right"android:layout_marginTop="5dp"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginRight="5dp"android:orientation="vertical"><TextViewandroid:id="@+id/my_name"android:layout_width="wrap_content"android:layout_height="0dp"android:layout_gravity="right"android:layout_weight="1" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="0dp"android:layout_weight="2"android:background="@drawable/my_bubble"><TextViewandroid:id="@+id/right_msg"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="8dp"android:gravity="center"android:textColor="@color/black"android:textSize="20dp" /></LinearLayout></LinearLayout><ImageViewandroid:id="@+id/head_my"android:layout_marginLeft="5dp"android:layout_width="60dp"android:layout_height="60dp" /></LinearLayout></LinearLayout>

Msg.java

package com.example.chartroom;public class Msg {public static final int TYPE_RECEIVED = 0;  //标记用于判断是输出消息还是接收消息public static final int TYPE_SENT = 1;private String content;       //存储消息信息private int type;   //存储判断信息private String time;private String name;private int imageId;public Msg(String content, int type, String time,String name,int imageId) {this.content = content;this.type = type;this.time = time;this.name = name;this.imageId = imageId;}public String getContent() {return content;}public int getType() {return type;}public String getTime(){return time;}public String getName(){return name;}public int getImageId(){return imageId;}
}

MsgAdapter.java

package com.example.chartroom;import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
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;
import java.util.zip.Inflater;public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder> {List<Msg> mMsgList;//把显示的数据源传进来public MsgAdapter(List<Msg> msgList) {super();mMsgList = msgList;}//创建ViewHolder实例@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);return new ViewHolder(view);}//对RecyclerView子项数据进行赋值@Overridepublic void onBindViewHolder(ViewHolder holder, int position) {Msg msg = mMsgList.get(position);holder.time.setText((CharSequence)msg.getTime());if(msg.getType() == Msg.TYPE_RECEIVED){  //接收端holder.his_head.setImageResource(msg.getImageId());holder.leftLayout.setVisibility(View.VISIBLE);  //左可见holder.rightLayout.setVisibility(View.GONE);    //右不可见holder.hisName.setText(msg.getName());holder.leftMsg.setText(msg.getContent());       //左边显示消息}else if(msg.getType() == Msg.TYPE_SENT){holder.my_head.setImageResource(msg.getImageId());holder.rightLayout.setVisibility(View.VISIBLE);holder.leftLayout.setVisibility(View.GONE);holder.name.setText(msg.getName());holder.rightMsg.setText(msg.getContent());}}//告诉RecycleView一共多少子项,返回数据源长度@Overridepublic int getItemCount() {return mMsgList.size();}public static class ViewHolder extends RecyclerView.ViewHolder {LinearLayout leftLayout ;LinearLayout rightLayout;TextView leftMsg;TextView rightMsg;TextView time;TextView name;TextView hisName;ImageView my_head;ImageView his_head;public ViewHolder(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);time = view.findViewById(R.id.time);              //显示时间name = view.findViewById(R.id.my_name);hisName = view.findViewById(R.id.others_name);my_head = view.findViewById(R.id.head_my);his_head = view.findViewById(R.id.head_others);}}
}

服务器

任意Java编译器即可,我用的IDEA

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;public class Server {public static void main(String[] args) {new Thread(new startServer()).start();}private static int port = 6666;public static ArrayList<UserThread> socketList = new ArrayList<UserThread>();private static class startServer extends Thread{public void run(){try {//绑定服务器要监听的端口ServerSocket serverSocket = new ServerSocket(port);while(true){//从队列中取出连接请求,使得队列能及时腾出空位,以容纳新的连接请求Socket socket = serverSocket.accept();System.out.println(""+socket);UserThread userThread = new UserThread(socket);socketList.add(userThread);new Thread(userThread).start();}} catch (IOException e) {e.printStackTrace();}}}private static class UserThread implements Runnable {private Socket skt;private DataInputStream dis;private DataOutputStream dos;public DataOutputStream getDos() {return dos;}public UserThread(Socket socket) {skt = socket;}//接收send过来的线程@Overridepublic void run() {try {dos = new DataOutputStream(skt.getOutputStream());dis = new DataInputStream(skt.getInputStream());while (true) {String r_content ;String name ;String time ;String imageId ;time = dis.readUTF();r_content = dis.readUTF();name = dis.readUTF();imageId = dis.readUTF();System.out.println("content = "+r_content);if(time == null){continue;}//发送出去for(UserThread ut : socketList){if(ut.equals(this)){  //是自己的消息就不发出System.out.println("自己的");continue;}try{System.out.println(time);//writeUTF在写入数据流的时候会加上两个字节以表示字节的长度ut.getDos().writeUTF(time);ut.getDos().writeUTF(r_content);ut.getDos().writeUTF(name);ut.getDos().writeUTF(imageId);System.out.println("写出去");//刷新ut.getDos().flush();}catch(Exception e){socketList.remove(ut);e.printStackTrace();}}}} catch (Exception e) {e.printStackTrace();}}}
}

Android小项目——聊天室相关推荐

  1. Android小项目————聊天室(UI篇)

    Android小项目----聊天室(UI篇) 一.前言 这是所做的第二个android项目,主要目的对暑假所学的java和android知识点进行复习巩固和实践,由于知识所限,目前这个聊天室并不是很完 ...

  2. Linux C小项目 —— 聊天室

    多线程的聊天室 服务器端: 实现多用户群体聊天功能(人数上限可设置): 每个用户所发送的消息,其他已连接服务器的用户均可以收到: 用户输入"bye"退出,服务器输入"qu ...

  3. Java小项目——聊天室(多线程版本)

    目录 1. 前言 2. 功能实现 3. 模块划分 4. 功能分析 4.1 前期分析 4.2 具体实现 5. 使用技术 6. 代码 1. 前言 之前写过单线程版本的聊天室,这次对之前的版本进行扩展与优化 ...

  4. C++小项目(聊天室)——select模型+mysql+花生壳端口映射打造一个可以用外网连接的小qq

    成品展示: B站视频链接 这个小软件是我初学网络编程写的小玩具,记录一下,等学完完成端口模型再利用完成端口写别的好玩的软件,看的课程是这个老师,真的强烈推荐,课程28块钱,老师讲的巨棒,很细,很适合新 ...

  5. Android 小项目之--数据存储【Files】(附源码)

    继上篇数据存储,现在我们来讲讲另外一种数据存储,Files.本篇讲述步骤如下: 1.温故而知新,复习四种数据存储的区别. 2.什么是 Files 数据存储. 3.什么是 Properties ? 4. ...

  6. php 小程序即时聊天,网易云IM小程序聊天室集成。PHP版SDK API使用示例

    搜索热词  出售微信小程序聊天室完整源码,也可定制开发微信小程序.扫码加微信详聊 /** 网易云信server API 接口使用示例 1.6 @author hzchensheng15@corp.ne ...

  7. linux 蓝牙 手机遥控器,嵌入式Android小项目之万能手机遥控器详解

    原标题:嵌入式Android小项目之万能手机遥控器详解 在很久很久以前,手机是有红外功能的,后来随着蓝牙技术的成熟,红外逐渐被蓝牙取代,不再是标配了. 红外本身还是有些优点,比如操作简便,成本低.要想 ...

  8. Android小项目———— 冰炭不投de小计算器

    我的第一个Android小项目 冰炭不投de小计算器 一.前言 这是我首个使用java写的app,也在学习郭霖老师的第一行代码和李刚老师的疯狂java讲义之时,进行的练习之作,刚刚学习java和and ...

  9. Android小项目——简易备忘录

    Android小项目--简易备忘录的实现 简易备忘录主要实现功能类似手机默认备忘录,可以对备忘录目录进行增添和删除.在编辑页面,可以显示当前时间,编辑备忘录标题,备忘录内容,设置时间提醒,插入图片等 ...

最新文章

  1. Log控制台打印设置
  2. atlsoap.h”: No such file or directory
  3. pandas中一列拆分成两列
  4. Qt中的四种信号与槽的连接方式
  5. 第一季6:海思方案中uboot、kernel和rootfs的烧写方法
  6. css中的换行符_如何使用CSS防止项目列表中的换行符?
  7. AIX6.1下WebLogic的nohup日志按天分割
  8. 怎么让前端项目运行起来_如何立即使您的前端项目看起来更好
  9. 博图买什么样配置的笔记本_3dsmax需要什么样的笔记本配置?
  10. IE6下实现Width:auto
  11. 禅道项目管理——bug管理工具
  12. 由浅入深玩转华为WLAN—12安全认证配置(5)Portal认证,外置Protal服务器TSM对接
  13. Not an managed type
  14. 2019年十大让人欲罢不能的消费潮流 | 财见年终观察
  15. 关于WPF的资源引用问题
  16. 神了!有人用一个项目把23种设计模式与六大原则融会贯通了
  17. uni-app卡片式轮播
  18. 职称计算机可以扣个税吗,哪些职业资格证书可以获得个税专项附加扣除和减免?...
  19. 每周全球科技十大新闻(2020.8.17-8.23)
  20. Suggestion: use tools:overrideLibrary

热门文章

  1. 如何成为一名oracle DBA
  2. 【 MATLAB 】sinc 函数简介
  3. 公开密钥密码学是什么
  4. Django的ORM操作篇
  5. Linux之挂载新的硬盘(超详细!)
  6. java字符串如何计算_关于Java:如何正确计算字符串字节?
  7. Mysql 数据库表中 int 类型的长度
  8. php合并数组并且去重,php合并数组
  9. 什么是RPC协议?RPC协议与HTTP协议的区别
  10. 益生元有什么作用?益生菌和益生元有什么关系?