欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Android聊天室开发(java写的后端服务)

程序员文章站 2022-05-16 22:26:16
用Android写的客户端,java写的服务端,这里简单的介绍一下我的客户端,想看服务端,源码的都可在我的博客查看效果展示代码展示分析1.添加权限,依赖库权限 uses-permission android:name=“android.permission.INTERNET”
用Android写的客户端,java写的服务端,这里简单的介绍一下我的客户端
服务端链接
源码链接

效果展示

Android聊天室开发(java写的后端服务)

Android聊天室开发(java写的后端服务)

代码展示分析

1.添加权限,依赖库
权限 uses-permission android:name=“android.permission.INTERNET”
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.uichat"> <uses-permission android:name="android.permission.INTERNET" /> <application ... </application> </manifest> 
依赖库
dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) ... implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha05' //recyclerview implementation 'org.litepal.guolindev:core:3.1.1' //LitePal } 
1.主页面
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout //约束布局 xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/ddd" tools:context=".MainActivity"> <androidx.constraintlayout.widget.Guideline //虚拟线,用于对下面布局进行约束 android:id="@+id/guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.45" /> <TextView
        android:id="@+id/username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="用户名" android:textSize="24sp" app:layout_constraintEnd_toStartOf="@id/guideline" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@id/login" app:layout_constraintVertical_chainStyle="packed" app:layout_constraintVertical_bias="0.4" android:layout_marginEnd="5dp" android:layout_marginRight="5dp" /> <EditText
        android:id="@+id/usernameEdit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" android:hint="输入用户名" app:layout_constraintBaseline_toBaselineOf="@id/username" app:layout_constraintStart_toEndOf="@id/guideline"/> <Button
        android:id="@+id/login" android:text="登录" android:textSize="18sp" android:layout_marginTop="10dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" app:layout_constraintTop_toBottomOf="@id/username" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> 
MainActivity
package com.example.uichat; 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; import android.widget.Toast; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ Button login; EditText loginedittext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); login = (Button)findViewById(R.id.login); loginedittext = (EditText)findViewById(R.id.usernameEdit); login.setOnClickListener(this); } @Override public void onClick(View view) { String name = loginedittext.getText().toString(); if("".equals(name)) Toast.makeText(MainActivity.this,"请输入用户名",Toast.LENGTH_SHORT).show(); else { //只要输入了名字就进入ChatUI界面 Intent intent = new Intent(MainActivity.this, ChatUI.class); intent.putExtra("username", name); startActivity(intent); } } } 
2.聊天页面
activity_chatui.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="match_parent" android:background="@drawable/eee" > <TextView
        android:id="@+id/top_TextView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.25" android:text="聊天室" android:gravity="center"/> <View
        android:layout_width="match_parent" android:layout_height="1dp" android:background="#FF909090"/> <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview_ChatUi" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="4" /> <LinearLayout
        android:layout_width="match_parent" android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1"> <View
            android:layout_width="match_parent" android:layout_height="1dp" android:background="#FF909090"/> <LinearLayout
            android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1" > <LinearLayout
                android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <EditText
                    android:id="@+id/ip_editText" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2"/> <Button
                    android:id="@+id/record" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:text="消息记录"/> <Button
                    android:id="@+id/cls" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:text="清屏"/> </LinearLayout> </LinearLayout> <View
            android:layout_width="match_parent" android:layout_height="1dp" android:background="#FF909090"/> <LinearLayout
           android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1"> <LinearLayout
                android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <EditText
                    android:id="@+id/send_editText" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3"/> <Button
                    android:id="@+id/send" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:text="Send"/> </LinearLayout> </LinearLayout> </LinearLayout> </LinearLayout> 
chatui.item.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"> <TextView
        android:id="@+id/item_data" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> <LinearLayout
        android:id="@+id/item_leftlinearlayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="left"> <ImageView
            android:id="@+id/item_leftImageView" android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/bbb" android:layout_margin="5dp" /> <LinearLayout
            android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView
                android:id="@+id/leftname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="5dp" android:layout_marginLeft="5dp" /> <LinearLayout
                android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/shadow_2" > <TextView
                    android:id="@+id/item_lefttextview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="5dp"/> </LinearLayout> </LinearLayout> </LinearLayout> <LinearLayout
        android:id="@+id/item_rightlinearlayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="right"> <LinearLayout
            android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView
                android:id="@+id/rightname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:layout_marginEnd="5dp" android:layout_marginRight="5dp" /> <LinearLayout
                android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/shadow_2" > <TextView
                    android:id="@+id/item_righttextview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="5dp"/> </LinearLayout> </LinearLayout> <ImageView
            android:id="@+id/item_rightImageView" android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/bbb" android:layout_margin="5dp" /> </LinearLayout> </LinearLayout> 
ChatUI
package com.example.uichat; import android.content.Intent; import android.os.Bundle; import android.os.Handler; 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.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.litepal.LitePal; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class ChatUI extends AppCompatActivity implements View.OnClickListener{ private String ip = "192.168.1.2"; //指定服务器ip private int port = 12345; //指定端口号 private boolean IStrue = false; //判断是否连接上服务器 private Socket socket; //我用DataInputStream,DataOutputStream来和服务器交互 private DataInputStream dis; private DataOutputStream dos; private RecyclerView recyclerView; private String myname; private int massage_type; private ChatAdapt adapt; private Button send; private Button record; private Button cls; private EditText ipedit; private EditText sendedit; private TextView toptext; private List<myChat> list = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_chatui); //必须重开一条线程不能放到主线程中,负责出现android.os.NetworkOnMainThreadException new Thread(new Runnable() { @Override public void run() { try { if( (socket = new Socket(ip,port))==null){ Toast.makeText(ChatUI.this,"连接服务器失败",Toast.LENGTH_SHORT).show(); }else{ IStrue = true; dis = new DataInputStream(socket.getInputStream()); dos = new DataOutputStream(socket.getOutputStream()); //开一条线程接收服务器传来的信息 new Thread(new Revised()).start(); } } catch (IOException e) { e.printStackTrace(); } } }).start(); Intent intent = getIntent(); myname = intent.getStringExtra("username"); //拿到主活动传来的name //用recyclerView来显示信息 recyclerView = (RecyclerView)findViewById(R.id.recyclerview_ChatUi); LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); adapt = new ChatAdapt(list); recyclerView.setAdapter(adapt); send = (Button)findViewById(R.id.send); record = (Button)findViewById(R.id.record); cls = (Button)findViewById(R.id.cls); ipedit = (EditText)findViewById(R.id.ip_editText); sendedit = (EditText)findViewById(R.id.send_editText); toptext = (TextView)findViewById(R.id.top_TextView); send.setOnClickListener(this); record.setOnClickListener(this); cls.setOnClickListener(this); } private void AutoDelete() { while (list.size()>20) //最多显示20条消息 list.remove(0); //这里吧刷新操作全放在 runOnUiThread中,不然会出现异常 runOnUiThread(new Runnable() { @Override public void run() { // 刷新操作 adapt.notifyDataSetChanged(); } }); } //接收服务器传来的信息 class Revised implements Runnable{ @Override public void run() { //这里必须无限循环,不然只能接到一条信息 while(true) { String title = null; String name = null; char[] temp = null; int len = 0; int massagetype = 0; char c = 0; //这里全是接收信息的,我接受三项信息title, name,temp try { temp = new char[200]; len = 0; while ((c = dis.readChar()) != '\t') { //用的‘\t’对信息做分割 temp[len] = c; len++; } title = new String(temp, 0, len); len = 0; while ((c = dis.readChar()) != '\t') { temp[len] = c; len++; } name = new String(temp, 0, len); massagetype = dis.readInt(); // Log.d("chatui",title+" 4567   "+name+""+massagetype); } catch (IOException e) { e.printStackTrace(); } String data = getdata(); //吧就收到的信息封装成 myChat对象,添加到集合中 myChat my = new myChat(title, name, data, myChat.TYPE_RESIVE, massagetype); list.add(my); AutoDelete(); runOnUiThread(new Runnable() { @Override public void run() { // 刷新操作 adapt.notifyDataSetChanged(); } }); } } } //按钮点击事件 @Override public void onClick(View view) { switch (view.getId()){ //如果点了发送要把信息显示到页面同时传给服务器 case R.id.send: { final String title = sendedit.getText().toString(); String data = getdata(); final String ip = ipedit.getText().toString().equals("")?"255.255.255.255":ipedit.getText().toString(); Log.d("ChatUI",ip); if(!"".equals(sendedit.getText().toString())){ if(ipedit.getText().toString().equals("")||ipedit.getText().toString().equals("255.255.255.255")) { massage_type = myChat.MESSAGE_PUBLIC; } else { massage_type = myChat.MESSAGE_PRIVATE; } //  Log.d("ChatUI",massage_type+""); if(IStrue){ //开一条线程把信息发给服务器,这里在按钮点击时无限循环,所以这里不用无限循环 new Thread(new Runnable() { @Override public void run() { try { dos.writeChars(title); dos.writeChar('\t'); dos.writeChars(myname); dos.writeChar('\t'); dos.writeChars(ip); dos.writeChar('\t'); Log.d("ChatUI","我发了"+title); } catch (IOException e) { e.printStackTrace(); } } }).start(); } else Toast.makeText(ChatUI.this,"发送失败",Toast.LENGTH_SHORT).show(); //把发出的信息封装成 myChat对象,添加到集合中 myChat my = new myChat(title,myname,data,myChat.TYPE_SEND,massage_type); list.add(my); AutoDelete(); runOnUiThread(new Runnable() { @Override public void run() { // 刷新操作 adapt.notifyDataSetChanged(); } }); sendedit.setText(""); addressed(title,myname,data); } break; } //清空页面的信息 case R.id.cls: { list.clear(); runOnUiThread(new Runnable() { @Override public void run() { // 刷新操作 adapt.notifyDataSetChanged(); } }); break; } //点了消息记录进入recordactivity活用于显示记录 case R.id.record:{ Intent intent = new Intent(ChatUI.this,recordactivity.class); startActivity(intent); break; } } } //获取时间 private String getdata() { Date data = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); return sdf.format(data); } //这里用LitPal操作数据库来保存数据,在发消息,收消息时都会用到,用于保存消息记录 private void addressed(String title, String name, String data) { record r = new record(); r.setTitle(title); r.setData(data); r.setName(name); r.save(); } } 
myChat
package com.example.uichat; public class myChat { public static final int TYPE_SEND = 1; //信息是发送的还是接收的 public static final int TYPE_RESIVE = 0; public static final int MESSAGE_PRIVATE = 1; //是私发信息还是群聊 public static final int MESSAGE_PUBLIC = 0; private String title; private int type; private int massagetype; public int getMassagetype() { return massagetype; } private String name; private String data; public String getData() { return data; } public myChat(String title, String name, String data,int type,int messagetype) { this.title = title; this.name = name; this.data = data; this.type = type; this.massagetype = messagetype; } public String getTitle() { return title; } public int getType() { return type; } public String getName() { return name; } } 
ChatAdapt
package com.example.uichat; import android.util.Log; 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 ChatAdapt extends RecyclerView.Adapter<ChatAdapt.ViewHolder> { private List<myChat> list; private String type_public = "[所有人]"; private String type_private = "[私有消息]"; static class ViewHolder extends RecyclerView.ViewHolder{ LinearLayout leftlinearLayout; LinearLayout rightlinearlayout; TextView item_data; TextView item_leftname; TextView item_rightname; TextView item_lefttitle; TextView item_righttitle; public ViewHolder(@NonNull View itemView) { super(itemView); leftlinearLayout =(LinearLayout)itemView.findViewById(R.id.item_leftlinearlayout); rightlinearlayout = (LinearLayout)itemView.findViewById(R.id.item_rightlinearlayout); item_data = (TextView)itemView.findViewById(R.id.item_data); item_rightname = (TextView)itemView.findViewById(R.id.rightname); item_leftname = (TextView)itemView.findViewById(R.id.leftname); item_lefttitle = (TextView)itemView.findViewById(R.id.item_lefttextview); item_righttitle = (TextView)itemView.findViewById(R.id.item_righttextview); } } public ChatAdapt(List<myChat> l){ list = l; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chatui_item,parent,false); ViewHolder holder = new ViewHolder(view); return holder; } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { myChat my = list.get(position); if(my.getType()==myChat.TYPE_RESIVE){ holder.leftlinearLayout.setVisibility(View.VISIBLE); //显示左边的 holder.rightlinearlayout.setVisibility(View.GONE); //右边隐藏 holder.item_data.setText(my.getData()); holder.item_lefttitle.setText(my.getTitle()); if(my.getMassagetype()==myChat.MESSAGE_PUBLIC){ holder.item_leftname.setText(type_public+"  "+my.getName()); } else if(my.getMassagetype()==myChat.MESSAGE_PRIVATE){ holder.item_leftname.setText(type_private+"  "+my.getName()); } } else if(my.getType()==myChat.TYPE_SEND){ holder.leftlinearLayout.setVisibility(View.GONE); //左边隐藏 holder.rightlinearlayout.setVisibility(View.VISIBLE); //右边显示 holder.item_data.setText(my.getData()); holder.item_righttitle.setText(my.getTitle()); Log.d("ChatUI",my.getMassagetype()+"  adapt"); if(my.getMassagetype()==myChat.MESSAGE_PUBLIC){ holder.item_rightname.setText(type_public+"  "+my.getName()); } else if(my.getMassagetype()==myChat.MESSAGE_PRIVATE){ holder.item_rightname.setText(type_private+"  "+my.getName()); } } } @Override public int getItemCount() { return list.size(); } } 
3.消息记录页面
这里用了LitePal操作数据库不懂可点击
activity_recordactivity.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" > <LinearLayout
        android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="horizontal"> <TextView
            android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="4" android:gravity="center" android:textSize="24sp" android:text="消息记录"/> <Button
            android:id="@+id/record_button" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:text = "清空记录"/> </LinearLayout> <View
        android:layout_width="match_parent" android:layout_height="1dp" android:background="#FF909090"/> <TextView
        android:layout_weight="9" android:id="@+id/recordtext" android:layout_margin="10dp" android:layout_width="match_parent" android:layout_height="0dp"/> </LinearLayout> 
recordactivity
package com.example.uichat; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import android.content.DialogInterface; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import org.litepal.LitePal; import java.util.ArrayList; import java.util.List; public class recordactivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recordactivity); final TextView text = (TextView)findViewById(R.id.recordtext); List<record> list = LitePal.findAll(record.class); String str =""; for(record r : list){ str += r.getData()+" "+r.getName()+":  "+r.getTitle() +"\n"; } text.setText(str); Button recorebutton = (Button)findViewById(R.id.record_button); recorebutton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { AlertDialog.Builder dialog = new AlertDialog.Builder(recordactivity.this); dialog.setTitle("This is Dialog"); dialog.setMessage("是否确定删除所有记录"); dialog.setCancelable(false); dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { LitePal.deleteAll(record.class); text.setText(""); } }); dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { } }); dialog.show(); } }); } } 
recoed
package com.example.uichat; import org.litepal.crud.LitePalSupport; public class record extends LitePalSupport { String title; String name; String data; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getData() { return data; } public void setData(String data) { this.data = data; } } 
litepal.xml
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="Record"></dbname> <version value="1"></version> <list> <mapping class="com.example.uichat.record"></mapping> </list> </litepal> 

本文地址:https://blog.csdn.net/haazzz/article/details/107755583