聊天室简介
简单介绍
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.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#2FF1EEEE">
<TextView
android: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>
<LinearLayout
android: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">
<TextView
android: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"/>
<EditText
android: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>
<LinearLayout
android: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">
<TextView
android: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"/>
<EditText
android: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>
<LinearLayout
android: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">
<TextView
android: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"/>
<EditText
android: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>
<LinearLayout
android: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">
<Button
android: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="连接"/>
<Button
android: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;
@Override
protected 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() {
@Override
public 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() {
@Override
public void onClick(View view) {
//用AlertDialog显示一个退出提示框
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("关闭提示");
dialog.setMessage("确定退出登录?");
dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
System.exit(0);
}
});
dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public 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.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#2FF1EEEE">
<TextView
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>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/one"
android:layout_width="0dp"
android:layout_height="115dp"
android:layout_weight="1"
android:background="@drawable/headofothers"
android:layout_margin="10dp"/>
<Button
android:id="@+id/two"
android:layout_width="0dp"
android:layout_height="115dp"
android:layout_weight="1"
android:background="@drawable/headofmy"
android:layout_margin="10dp"/>
<Button
android:id="@+id/three"
android:layout_width="0dp"
android:layout_height="115dp"
android:layout_weight="1"
android:background="@drawable/three"
android:layout_margin="10dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/four"
android:layout_width="0dp"
android:layout_height="115dp"
android:layout_weight="1"
android:background="@drawable/six"
android:layout_margin="10dp"/>
<Button
android:id="@+id/five"
android:layout_width="0dp"
android:layout_height="115dp"
android:layout_weight="1"
android:background="@drawable/four"
android:layout_margin="10dp"/>
<Button
android: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;
@Override
public 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);
}
@Override
public 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; //判断是否发送
@Override
protected 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() {
@Override
public 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);
}
@Override
public 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() {
@Override
public 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()){
@Override
public 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{
@Override
public 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
要显示<这个标识符的话,得写成:"<,"
<?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.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#2FF1EEEE">
<Button
android:id="@+id/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:textSize="30sp"
android:background="#00FFFFFF"
android:text="<"/>
<TextView
android: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.RecyclerView
android:id="@+id/msg_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp">
<EditText
android: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" />
<Button
android: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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<TextView
android: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>
<LinearLayout
android:id="@+id/left_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="5dp">
<ImageView
android:id="@+id/head_others"
android:layout_marginRight="5dp"
android:layout_width="60dp"
android:layout_height="60dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="5dp">
<TextView
android:id="@+id/others_name"
android:layout_gravity="left"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:background="@drawable/his_bubble">
<TextView
android: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>
<LinearLayout
android:id="@+id/right_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="5dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:orientation="vertical">
<TextView
android:id="@+id/my_name"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="right"
android:layout_weight="1" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="2"
android:background="@drawable/my_bubble">
<TextView
android: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>
<ImageView
android: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实例
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);
return new ViewHolder(view);
}
//对RecyclerView子项数据进行赋值
@Override
public 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一共多少子项,返回数据源长度
@Override
public 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过来的线程
@Override
public 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();
}
}
}
}