为什么这里要有聊天室(一)呢?其实这个是我的Java项目。之前写了个Java聊天室,虽然不是很完美但是,运行起来问题也不大。能较完美的运行我的聊天室Java代码也贴上吧。好做复习使用。
共分为四个类。
1、服务器类
package chatting;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class MultiTalkServer {
static int i = 0;
static int clientNum = 0;
//容器:储存每一个用户的socket
private List<ServerThread> servers = new ArrayList<ServerThread>();
public static void main(String[] args) throws IOException{
new MultiTalkServer().startChatting();
}
//主函数
public void startChatting() throws IOException{
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4477);
}catch(Exception e){
System.out.println("couldn't listen on port");
System.exit(-1);
}
while ( listening ){
Socket socket = serverSocket.accept();
System.out.println("有客户端已连接!");
ServerThread serverThread = new ServerThread(socket,clientNum);
//将创建的线程放入容器
servers.add(serverThread);
new Thread(serverThread).start();
clientNum++;
}
serverSocket.close();
}
//多线程创建多个用户可共享的服务器,为方便访问内部变量,故设为内部类线程
private class ServerThread implements Runnable {
Socket socket = null;
private String line;
private int clientNum;
private BufferedReader is;
private PrintWriter os;
public ServerThread(Socket socket,int num){
this.socket = socket;
this.clientNum = num + 1;
}
public void run(){
try{
is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
os = new PrintWriter(socket.getOutputStream());
line = clientNum + ":" + is.readLine();
while (!line.equals(clientNum + ":" + "bye")){
//遍历容器,当遍历到自身时不发送,否则发送
for(ServerThread others:servers){
if (others == this){
continue;
}
others.send(line);
}
System.out.println(line);
line = clientNum + ":" + is.readLine();
}
os.close();
is.close();
socket.close();
}catch (Exception e){
System.out.println("Error: " + e);
}
}
//服务器发送数据
private void send(String msg){
os.println(msg);
os.flush();
}
}
}
2、客户类
package chatting;
import java.net.Socket;
public class TalkClient {
static boolean tag = true;
public static void main(String[] args) {
try{
//向本机的4477端口发出客户请求
Socket socket = new Socket("127.0.0.1",4477);
new Thread(new sendThread(socket)).start();
new Thread(new ReceiveThread(socket)).start();
if (!tag) socket.close();
} catch (Exception e){
System.out.println("Error:" + e);
}
}
}
3、客户端接收消息线程package chatting;
import java.io.*;
import java.net.Socket;
public class ReceiveThread implements Runnable {
private BufferedReader is;
private String msg;
public ReceiveThread(Socket socket){
try {
is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
while (!msg.equals("bye")){
System.out.println("client " + msg);
msg = is.readLine();
}
} catch (IOException e) {
// e.printStackTrace();
}
}
}
4、客户端发消息线程
package chatting;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class sendThread implements Runnable {
private BufferedReader is ;
private PrintWriter os;
String msg;
public sendThread(Socket socket){
try {
is = new BufferedReader(new InputStreamReader(System.in));
os = new PrintWriter(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
msg = is.readLine();
while (!msg.equals("bye")) {
os.println(msg);
os.flush();
System.out.println("Server:" + msg);
msg = is.readLine();
}
TalkClient.tag = false;
} catch (IOException e) {
// e.printStackTrace();
}
}
}
这个程序可以实现最简单的聊天。运行顺序就是先运行服务器端,在运行客户端,打开一个客户端就是创建了一个客户端,了两个就是创建了两个。
由于正在学习安卓,所以准备把他移植到 安卓上。起初想的是,就是把客户端输出换成了EditText显示,客户端接收换成了RecyclerView显示,应该很简单,但是,事实证明我想多了。
首先创建一个RecyclerView,方法很正常。首先是layout.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:orientation="vertical">
<android.support.v7.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">
<EditText
android:id="@+id/input_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Please Input"
android:maxLines="2" />
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
其次是msgitem.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<LinearLayout
android:id="@+id/left_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_left"
android:layout_gravity="left">
<TextView
android:id="@+id/left_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/right_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_right"
android:layout_gravity="right"
>
<TextView
android:layout_gravity="center"
android:layout_margin="10dp"
android:id="@+id/right_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
接着是Msg.java和MsgAdapter.javapackage com.example.administrator.chattingroom;
public class Msg {
public static final int TYPE_RECEIVED = 0;
public static final int TYPE_SEND = 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.administrator.chattingroom;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
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;
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);
}
}
public MsgAdapter(List<Msg> msgList){
mMsgList = msgList;
}
@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);
}
@Override
public void onBindViewHolder(MsgAdapter.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_SEND){
holder.rightLayout.setVisibility(View.VISIBLE);
holder.leftLayout.setVisibility(View.GONE);
holder.rightMsg.setText(msg.getContent());
}
}
@Override
public int getItemCount() {
return mMsgList.size();
}
}
这样子准备工作 就做完了。接下来就是功能代码的实现了。第一是服务器代码,照搬,根本没有影响。就下来就是MainActivity.java的写法了。
开始我不管怎么改都无法连上服务器,就很伤,百度,百度,却怎么也找不到错误原因,最后在一个不知名的地方找到了我的原因,原来如果我想像Java那样直接链接到本机ip就不能用127.0.0.1了,因为安卓的ip默认的本机ip是10.0.2.2,所以在服务器端的socket声明就应该是
client = new Socket("10.0.2.2", 4477);
但是接着又出现问题了,由于安卓规定网络申请不能在主线程中。所以没办法只能在主线程中再开一个线程了。最后当我感觉到万事俱备,只欠东风之时,又出问题了,从服务器接收到的信息不能同步到手机显示上面。。。。后来查了一下,需要使用一个Handler函数进行刷屏,终于跌跌撞撞的完成了。哎,不容易。
package com.example.administrator.chattingroom;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import org.w3c.dom.Text;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private String receive;
static boolean tag = true;
private String message;
private List<Msg> msgList = new ArrayList<>();
private EditText inputText,show;
private Button send;
private RecyclerView msgRecyclerView;
private MsgAdapter adapter;
private Socket client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
// initMsgs();
inputText = findViewById(R.id.input_text);
send = findViewById(R.id.send);
msgRecyclerView = findViewById(R.id.msg_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
msgRecyclerView.setLayoutManager(layoutManager);
adapter = new MsgAdapter(msgList);
msgRecyclerView.setAdapter(adapter);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final String content = inputText.getText().toString();
new Thread(){
@Override
public void run() {
try {
PrintWriter os = new PrintWriter(client.getOutputStream());
os.println(content);
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
message = content;
System.out.println(message);
if (!"".equals(content)){
Msg msg = new Msg(content,Msg.TYPE_SEND);
msgList.add(msg);
adapter.notifyItemInserted(msgList.size()-1);
msgRecyclerView.scrollToPosition(msgList.size()-1);
inputText.setText("");
}
}
});
// new Thread(new ReceiveThread(client)).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
client = new Socket("10.0.2.2", 4477);
BufferedReader is = new BufferedReader(new InputStreamReader(client.getInputStream()));
receive = is.readLine();
System.out.println(receive);
Message message = new Message();
message.what = 1;
String[] aa = receive.split(":",2);
message.obj = aa[1];
handler.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1){
Msg msg1 = new Msg(msg.obj.toString(),Msg.TYPE_RECEIVED);
msgList.add(msg1);
adapter.notifyItemInserted(msgList.size()-1);
msgRecyclerView.scrollToPosition(msgList.size()-1);
}
}
};
// private void initMsgs(){
// Msg msg1 = new Msg("Hello guy.",Msg.TYPE_RECEIVED);
// msgList.add(msg1);
// Msg msg2 = new Msg("Hello,who is that?",Msg.TYPE_SEND);
// msgList.add(msg2);
// }
}
最后记住申请网络访问权限。
按程序大致就这样当时还是有BUG。
就是只能你一句我一句的发,不知道怎么该,还有好多问题emmmm啊啊啊,安卓真难,不容易不容易。。。
这两天不再学安卓了。要期末考试了,只能专心应付考试了